Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Halbear
cb12591f5d funny world gen (translated Terrain4J's noise to rust for funsies) 2026-09-05 21:51:55 +01:00
6 changed files with 292 additions and 26 deletions

62
Cargo.lock generated
View file

@ -31,7 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"getrandom",
"getrandom 0.3.4",
"once_cell",
"version_check",
"zerocopy",
@ -652,6 +652,8 @@ dependencies = [
"log",
"mars",
"pollster",
"rand",
"rand_chacha",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@ -669,6 +671,17 @@ dependencies = [
"windows-link",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "getrandom"
version = "0.3.4"
@ -990,7 +1003,7 @@ version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom",
"getrandom 0.3.4",
"libc",
]
@ -1659,6 +1672,15 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "presser"
version = "0.3.1"
@ -1719,6 +1741,36 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "range-alloc"
version = "0.1.5"
@ -2222,6 +2274,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
version = "1.0.3+wasi-0.2.9"

View file

@ -24,6 +24,8 @@ console_error_panic_hook = "0.1.7"
bytemuck = { version = "1.25.0", features = [ "derive" ]}
image = { version = "0.24", default-features = false, features = ["png", "jpeg"]}
mars = { path = "../Mars" }
rand = "0.8"
rand_chacha = "0.3"
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"

View file

@ -2,6 +2,8 @@ use std::collections::HashMap;
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
use crate::render::Renderer;
use crate::world::{SimpleObject, World};
use crate::permutation_array;
use crate::noise2d;
use glam::{Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4};
use std::sync::Arc;
#[cfg(target_arch = "wasm32")]
@ -16,6 +18,8 @@ use winit::{
keyboard::{KeyCode, PhysicalKey},
window::Window,
};
use crate::noise2d::Noise2D;
use crate::permutation_array::PermutationArray;
struct Controller {
buttons: HashMap<MouseButton, bool>,
@ -38,9 +42,12 @@ pub struct AppState {
controller: Controller,
window: Arc<Window>,
clients: Vec<SimpleObject>,
chunks: Vec<(i32, i32)>,
Permutation: PermutationArray,
}
const BLOCKS: i32 = 1;
const BLOCKS: i32 = 100;
impl AppState {
// We don't need this to be async right now,
@ -48,6 +55,9 @@ impl AppState {
pub async fn new(window: Arc<Window>) -> Result<AppState, Box<dyn std::error::Error>> {
let mut world = World::new();
world.add_renderer(Renderer::new(&window).await?);
let mut Permutation: PermutationArray = PermutationArray::new();
Permutation.generate_permutation_array(0);
let mut chunks = Vec::new();
let mut clients = Vec::new();
{
let file = world
@ -65,35 +75,39 @@ impl AppState {
//let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"));
//let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"));
//let mat = renderer.new_material(color,normal,roughness);
for x in -BLOCKS..BLOCKS {
for y in -BLOCKS..BLOCKS {
let block = block.hard_clone();
world.add_object(block.clone());
{
let mut model = block.0.borrow_mut();
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0),
)
* Mat4::from_rotation_z((x * y) as f32 / 1.23);
model.model.as_mut().unwrap().instance.color = Vec4::new(
0.3,
(x + BLOCKS) as f32 / BLOCKS as f32,
(y + BLOCKS) as f32 / BLOCKS as f32,
1.0,
);
}
clients.push(block)
}
}
// for x in -BLOCKS..BLOCKS {
// for y in -BLOCKS..BLOCKS {
// let block = block.hard_clone();
// world.add_object(block.clone());
// {
// let mut model = block.0.borrow_mut();
// model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
// Vec3::new(-x as f32 * 1.0, Noise2D::fractal_noise(x as f64 * 0.1, y as f64*0.1, 5, 10.0, 0.05, &Permutation).round() as i64 as f32, -y as f32 * 1.0),
// )
// * Mat4::from_rotation_z(0f32 /*(x * y) as f32 / 1.23*/);
// model.model.as_mut().unwrap().instance.color = Vec4::new(
// 0.3,
// (x + BLOCKS) as f32 / BLOCKS as f32,
// (y + BLOCKS) as f32 / BLOCKS as f32,
// 1.0,
// );
// }
// clients.push(block)
// }
// }
}
Ok(Self {
world,
clients,
controller: Controller::new(),
window,
chunks,
Permutation
})
}
pub fn bounds(&self) -> (u32, u32) {
let size = self.window.inner_size();
(size.width, size.height)
@ -152,6 +166,42 @@ impl App {
proxy,
}
}
pub fn GenerateChunk(ChunkX: i32, ChunkY: i32, size: i32, state: &mut AppState){
if(state.chunks.contains(&(ChunkX, ChunkY))){
return;
}
let file = state.world
.renderer
.as_mut()
.unwrap()
.load_from_gltf(include_bytes!("assets/cube.glb"));
let block = file.first_object().unwrap();
for x in 0..size {
for y in 0..size {
let worldPosX = ChunkX * size + x;
let worldPosY = ChunkY * size + y;
let block = block.hard_clone();
state.world.add_object(block.clone());
{
let mut model = block.0.borrow_mut();
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
Vec3::new(worldPosX as f32 * 1.0, Noise2D::fractal_noise(worldPosX as f64 * 0.25, worldPosY as f64*0.25, 10, 20.0, 0.05, &state.Permutation).round() as i64 as f32, worldPosY as f32 * 1.0),
)
* Mat4::from_rotation_z(0f32 /*(x * y) as f32 / 1.23*/);
model.model.as_mut().unwrap().instance.color = Vec4::new(
0.3,
(x + size) as f32 / size as f32,
(y + size) as f32 / size as f32,
1.0,
);
}
state.clients.push(block);
}
}
state.chunks.push((ChunkX, ChunkY));
}
}
impl ApplicationHandler<AppState> for App {
@ -261,13 +311,28 @@ impl ApplicationHandler<AppState> for App {
movement.y -= 1.0;
}
let PosX = state.world.renderer.as_ref().unwrap().eye.frame.translation.x;
let Posy = state.world.renderer.as_ref().unwrap().eye.frame.translation.z;
let WorldPosX = (PosX / 16.0).floor() as i32;
let WorldPosY = (Posy / 16.0).floor() as i32;
let startX = WorldPosX - 5;
let endX = WorldPosX + 5;
let startY = WorldPosY - 5;
let endY = WorldPosY + 5;
for x in startX..endX {
for y in startY..endY {
App::GenerateChunk(x, y, 16, state);
}
}
state
.world
.renderer
.as_mut()
.unwrap()
.eye
.control(movement * 0.1);
.control(movement * 0.5);
match state.world.renderer.as_mut().unwrap().render(&state.window) {
Ok(_) => {}
Err(e) => {
@ -285,7 +350,7 @@ impl ApplicationHandler<AppState> for App {
.unwrap()
.instance
.transform *= Mat4::from_rotation_translation(
Quat::from_euler(EulerRot::XYZ, 0.001, -0.001, 0.001),
Quat::from_euler(EulerRot::XYZ,0.00,0.00,0.00 /*0.001, -0.001, 0.001*/),
Vec3::new(0.0, 0.0, 0.0),
);
}
@ -308,6 +373,9 @@ impl ApplicationHandler<AppState> for App {
_ => {}
}
}
}
pub fn run() -> anyhow::Result<()> {

View file

@ -2,4 +2,6 @@
pub mod app;
pub mod render;
pub mod web;
pub mod world;
pub mod world;
pub mod permutation_array;
pub mod noise2d;

97
src/noise2d.rs Normal file
View file

@ -0,0 +1,97 @@
use crate::permutation_array;
use crate::permutation_array::PermutationArray;
#[derive(Debug, Clone, Copy)]
pub struct Vector2d {
pub x: f64,
pub y: f64,
}
impl Vector2d {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
pub fn dot(&self, other: Vector2d) -> f64 {
self.x * other.x + self.y * other.y
}
}
pub struct Noise2D;
impl Noise2D {
pub fn gen_gradient_vector(p: i32) -> Vector2d {
match p & 3 {
0 => Vector2d::new(1.0, 1.0),
1 => Vector2d::new(-1.0, 1.0),
2 => Vector2d::new(-1.0, -1.0),
_ => Vector2d::new(1.0, -1.0),
}
}
fn fade(t: f64) -> f64 {
t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
}
fn lerp(t: f64, x: f64, y: f64) -> f64 {
x + t * (y - x)
}
pub fn noise_2d(x: f64, y: f64, permutation: &[i32; 512]) -> f64 {
let x_floor = x.floor();
let y_floor = y.floor();
let x_grid = (x_floor as i32) & 255;
let y_grid = (y_floor as i32) & 255;
let xd = x - x_floor;
let yd = y - y_floor;
let tr = Vector2d::new(xd - 1.0, yd - 1.0);
let tl = Vector2d::new(xd, yd - 1.0);
let br = Vector2d::new(xd - 1.0, yd);
let bl = Vector2d::new(xd, yd);
let x_idx = x_grid as usize;
let y_idx = y_grid as usize;
let value_tr = permutation[permutation[x_idx + 1] as usize + y_idx + 1];
let value_tl = permutation[permutation[x_idx] as usize + y_idx + 1];
let value_br = permutation[permutation[x_idx + 1] as usize + y_idx];
let value_bl = permutation[permutation[x_idx] as usize + y_idx];
let d_tr = tr.dot(Self::gen_gradient_vector(value_tr));
let d_tl = tl.dot(Self::gen_gradient_vector(value_tl));
let d_br = br.dot(Self::gen_gradient_vector(value_br));
let d_bl = bl.dot(Self::gen_gradient_vector(value_bl));
let u = Self::fade(xd);
let v = Self::fade(yd);
Self::lerp(
u,
Self::lerp(v, d_bl, d_tl),
Self::lerp(v, d_br, d_tr),
)
}
pub fn fractal_noise(
x: f64,
y: f64,
octaves: i32,
mut amplitude: f64,
mut frequency: f64,
permutation: &PermutationArray,
) -> f64 {
let mut fractal_noise = 0.0;
for _ in 0..octaves {
let layer = amplitude * Self::noise_2d(x * frequency, y * frequency, permutation.get_permutation());
fractal_noise += layer;
amplitude *= 0.5;
frequency *= 2.0;
}
fractal_noise
}
}

39
src/permutation_array.rs Normal file
View file

@ -0,0 +1,39 @@
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
//i translated the Terrain4J Noise2D to Rust so i can mess around with the cubes
pub struct PermutationArray {
permutation: [i32; 512],
}
impl PermutationArray {
pub fn new() -> Self {
Self {
permutation: [0; 512],
}
}
pub fn get_permutation(&self) -> &[i32; 512] {
&self.permutation
}
pub fn generate_permutation_array(&mut self, seed: i64) {
let mut seed_bytes = [0u8; 32];
seed_bytes[0..8].copy_from_slice(&(seed as u64).to_le_bytes());
let mut rnd = ChaCha8Rng::from_seed(seed_bytes);
self.permutation = [0; 512];
for i in 0..256 {
self.permutation[i] = i as i32;
}
for p in (1..256).rev() {
let index = rnd.gen_range(0..=p);
self.permutation.swap(p, index);
}
for i in 0..256 {
self.permutation[i + 256] = self.permutation[i];
}
}
}