Initial commit
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -14,3 +14,8 @@ Cargo.lock
|
|||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
||||||
|
|||||||
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'DayNight'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=DayNight",
|
||||||
|
"--package=DayNight"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "DayNight",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'DayNight'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=DayNight",
|
||||||
|
"--package=DayNight"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "DayNight",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "DayNight"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pixels = "0.13.0"
|
||||||
|
env_logger = "0.10"
|
||||||
|
log = "0.4"
|
||||||
|
winit = "0.28"
|
||||||
|
winit_input_helper = "0.14"
|
||||||
|
randomize = "5.0.0"
|
||||||
|
getrandom = "0.2.15"
|
||||||
|
byteorder = "1"
|
||||||
|
noise = "0.9"
|
||||||
23
src/cell.rs
Normal file
23
src/cell.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum CellVariance {
|
||||||
|
VOID = 0,
|
||||||
|
DAY = 1,
|
||||||
|
NIGHT = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CellVariance {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::VOID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct Cell {
|
||||||
|
pub variance: CellVariance
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cell {
|
||||||
|
pub fn new(variance: CellVariance) -> Self {
|
||||||
|
Self { variance }
|
||||||
|
}
|
||||||
|
}
|
||||||
88
src/main.rs
Normal file
88
src/main.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
mod cell;
|
||||||
|
mod stage;
|
||||||
|
|
||||||
|
use pixels::{Error, Pixels, SurfaceTexture};
|
||||||
|
use stage::Stage;
|
||||||
|
use winit::{
|
||||||
|
dpi::LogicalSize,
|
||||||
|
event::{Event, VirtualKeyCode},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::{self, WindowBuilder},
|
||||||
|
};
|
||||||
|
use winit_input_helper::WinitInputHelper;
|
||||||
|
|
||||||
|
const WIDTH: u32 = 256;
|
||||||
|
const HEIGHT: u32 = 256;
|
||||||
|
const SCALE_FACTOR: f64 = 4.0;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
let mut input = WinitInputHelper::new();
|
||||||
|
|
||||||
|
let window = {
|
||||||
|
let size: LogicalSize<f64> = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
||||||
|
let scaled_size =
|
||||||
|
LogicalSize::new(WIDTH as f64 * SCALE_FACTOR, HEIGHT as f64 * SCALE_FACTOR);
|
||||||
|
|
||||||
|
WindowBuilder::new()
|
||||||
|
.with_title("Day and Night")
|
||||||
|
.with_inner_size(scaled_size)
|
||||||
|
.with_min_inner_size(size)
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pixels = {
|
||||||
|
let window_size = window.inner_size();
|
||||||
|
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||||
|
Pixels::new(WIDTH, HEIGHT, surface_texture)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stage = Stage::new(WIDTH as usize, HEIGHT as usize);
|
||||||
|
stage.scatter(stage::ScatterTypes::RANDOM);
|
||||||
|
|
||||||
|
let mut paused = false;
|
||||||
|
|
||||||
|
let mut draw_state: Option<bool> = None;
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
if let Event::RedrawRequested(_) = event {
|
||||||
|
stage.draw(pixels.frame_mut());
|
||||||
|
|
||||||
|
if let Err(err) = pixels.render() {
|
||||||
|
debug_assert!(true, "Oops, I did it again.");
|
||||||
|
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.update(&event) {
|
||||||
|
if input.key_pressed(VirtualKeyCode::Escape) || input.close_requested() {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.key_pressed(VirtualKeyCode::R) {
|
||||||
|
stage.scatter(stage::ScatterTypes::RANDOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the window
|
||||||
|
if let Some(size) = input.window_resized() {
|
||||||
|
if let Err(err) = pixels.resize_surface(size.width, size.height) {
|
||||||
|
debug_assert!(true, "Resize failed!");
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !paused || input.key_pressed_os(VirtualKeyCode::Space) {
|
||||||
|
stage.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
106
src/stage.rs
Normal file
106
src/stage.rs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
use noise::core::value;
|
||||||
|
use noise::core::value::value_2d;
|
||||||
|
use noise::permutationtable::PermutationTable;
|
||||||
|
use noise::utils::NoiseMapBuilder;
|
||||||
|
use noise::utils::PlaneMapBuilder;
|
||||||
|
use noise::BasicMulti;
|
||||||
|
use noise::Fbm;
|
||||||
|
use noise::Perlin;
|
||||||
|
use noise::Seedable;
|
||||||
|
use randomize::Gen32;
|
||||||
|
use randomize::PCG32;
|
||||||
|
|
||||||
|
use crate::cell::Cell;
|
||||||
|
use crate::cell::CellVariance;
|
||||||
|
pub struct Stage {
|
||||||
|
cells: Vec<Cell>,
|
||||||
|
|
||||||
|
/// Used for temporary work item. Replaces `cells` once done.
|
||||||
|
cells_dup: Vec<Cell>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ScatterTypes {
|
||||||
|
RANDOM = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stage {
|
||||||
|
pub fn new(width: usize, height: usize) -> Self {
|
||||||
|
assert!(width != 0 && height != 0);
|
||||||
|
let size = width.checked_mul(height).expect("Given width is too big.");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cells: vec![Cell::default(); size],
|
||||||
|
cells_dup: vec![Cell::default(); size],
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a pseudorandom seed for the game's PRNG.
|
||||||
|
fn generate_seed() -> (u64, u64) {
|
||||||
|
use byteorder::{ByteOrder, NativeEndian};
|
||||||
|
use getrandom::getrandom;
|
||||||
|
|
||||||
|
let mut seed = [0_u8; 16];
|
||||||
|
|
||||||
|
getrandom(&mut seed).expect("failed to getrandom");
|
||||||
|
|
||||||
|
(
|
||||||
|
NativeEndian::read_u64(&seed[0..8]),
|
||||||
|
NativeEndian::read_u64(&seed[8..16]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scatter(&mut self, scatter: ScatterTypes) {
|
||||||
|
match scatter {
|
||||||
|
ScatterTypes::RANDOM => {
|
||||||
|
let seed = Self::generate_seed();
|
||||||
|
let mut rng: randomize::PCG32 = PCG32::new(seed.0, seed.1);
|
||||||
|
|
||||||
|
let basicmulti = BasicMulti::<Perlin>::new(rng.next_u32());
|
||||||
|
|
||||||
|
let plane = PlaneMapBuilder::new(basicmulti)
|
||||||
|
.set_size(self.width, self.height)
|
||||||
|
.set_x_bounds(-5.0, 5.0)
|
||||||
|
.set_y_bounds(-5.0, 5.0)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
let mut variance = CellVariance::VOID;
|
||||||
|
|
||||||
|
let value = plane.get_value(x, y);
|
||||||
|
if value <= 0.1 {
|
||||||
|
variance = CellVariance::DAY;
|
||||||
|
} else {
|
||||||
|
variance = CellVariance::NIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = self.cells.get_mut(x + y * self.width).unwrap();
|
||||||
|
*cell = Cell::new(variance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, screen: &mut [u8]) {
|
||||||
|
debug_assert_eq!(screen.len(), 4 * self.cells.len());
|
||||||
|
for (c, pix) in self.cells.iter().zip(screen.chunks_exact_mut(4)) {
|
||||||
|
let color = match c.variance {
|
||||||
|
CellVariance::VOID => [0x0, 0x0, 0x0, 0xFF],
|
||||||
|
CellVariance::DAY => [0xD3, 0xE3, 0xD3, 0xFF],
|
||||||
|
CellVariance::NIGHT => [0x10, 0x41, 0x4F, 0xFF],
|
||||||
|
};
|
||||||
|
pix.copy_from_slice(&color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
std::mem::swap(&mut self.cells_dup, &mut self.cells);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user