mirror of
https://github.com/Cactus-minecraft-server/World.git
synced 2025-12-07 10:40:37 +00:00
refactor worldgen
This commit is contained in:
@@ -4,9 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
noise = "0.9.0"
|
|
||||||
image = "0.25.5"
|
|
||||||
rayon = "1.10.0"
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "worldgen"
|
name = "worldgen"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|||||||
16
src/.vscode/launch.json
vendored
Normal file
16
src/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// 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",
|
||||||
|
"program": "${workspaceFolder}/<executable file>",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
115
src/lib.rs
115
src/lib.rs
@@ -1,59 +1,70 @@
|
|||||||
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
pub struct Noise {
|
||||||
|
|
||||||
/// Generates a 16x16 noise map for a given chunk using fractal noise with multiple octaves
|
|
||||||
/// to avoid repetitive patterns.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
/// - `seed`: A number influencing the noise generation (e.g., 42).
|
|
||||||
/// - `chunk_x`: The X coordinate of the chunk.
|
|
||||||
/// - `chunk_z`: The Z coordinate of the chunk.
|
|
||||||
/// - `scale`: The noise scale (smaller = more detailed noise).
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - A **16x16 noise map** as `[[f64; 16]; 16]`, normalized between -64 and 324.
|
|
||||||
pub fn generate_normalized_noise_map(
|
|
||||||
seed: u32,
|
|
||||||
chunk_x: i32,
|
|
||||||
chunk_z: i32,
|
|
||||||
scale: f64,
|
scale: f64,
|
||||||
) -> [[f64; 16]; 16] {
|
amplitude: f64,
|
||||||
// Spécifier explicitement que Fbm utilise Perlin comme bruit de base
|
}
|
||||||
let fbm = Fbm::<Perlin>::new(seed).set_octaves(15);
|
pub struct Vector {
|
||||||
let mut noise_map = [[0.0; 16]; 16];
|
x: f32,
|
||||||
|
y: f32,
|
||||||
// Define normalization range
|
}
|
||||||
let min_range = -64.0;
|
impl Noise {
|
||||||
let max_range = 320.0;
|
pub fn new(scale: f64, amplitude: f64) -> Self {
|
||||||
|
Self { scale, amplitude }
|
||||||
for x in 0..16 {
|
}
|
||||||
for z in 0..16 {
|
pub fn get(&self, x: f64, z: f64) -> f64 {
|
||||||
// Convert chunk-local coordinates to global world coordinates
|
let xs = x / self.scale;
|
||||||
let world_x = (chunk_x * 16 + x as i32) as f64 * scale;
|
let zs = z / self.scale;
|
||||||
let world_z = (chunk_z * 16 + z as i32) as f64 * scale;
|
self.perlin(xs, zs) * self.amplitude
|
||||||
|
}
|
||||||
// Generate fractal noise value (with multiple octaves)
|
fn perlin(&self, x: f64, z: f64) -> f64 {
|
||||||
let noise_value = fbm.get([world_x, world_z]);
|
// implement Perlin noise here (then simplex because it's harder)
|
||||||
|
todo!()
|
||||||
// Normalize noise from [-1,1] to [-64,324]
|
}
|
||||||
let normalized_noise = (noise_value + 1.0) / 2.0 * (max_range - min_range) + min_range;
|
}
|
||||||
|
fn dot_product(v1: Vector, v2: Vector) -> f32 {
|
||||||
// Store the normalized noise value
|
// Calculate the dot product between v1 and v2 using their coordinates. the result->f32.
|
||||||
noise_map[x][z] = normalized_noise;
|
v1.x * v2.x + v1.y * v2.y
|
||||||
}
|
}
|
||||||
}
|
fn calculate_norm(v1: &Vector) -> f32 {
|
||||||
noise_map
|
// Calculate the norm of a vector using it's coordinates. the result -> f32.
|
||||||
|
(v1.x.powi(2) + v1.y.powi(2)).sqrt()
|
||||||
|
}
|
||||||
|
fn normalize(v1: &Vector) -> Vector {
|
||||||
|
// This function aim that every vector created randomly has the same norm (1).
|
||||||
|
Vector {
|
||||||
|
x: v1.x / calculate_norm(v1),
|
||||||
|
y: v1.y / calculate_norm(v1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use crate::{Vector, calculate_norm, dot_product, normalize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_generate_normalized_noise_map() {
|
fn test_dot_product() {
|
||||||
let noise_map = generate_normalized_noise_map(456, 0, 0, 0.1);
|
assert_eq!(
|
||||||
assert_eq!(noise_map.len(), 16);
|
dot_product(Vector { x: 1.0, y: 0.0 }, Vector { x: 0.0, y: 1.0 }),
|
||||||
for row in noise_map.iter() {
|
0.0
|
||||||
assert_eq!(row.len(), 16);
|
);
|
||||||
}
|
assert_eq!(
|
||||||
|
dot_product(Vector { x: 1.0, y: 0.5 }, Vector { x: 0.2, y: 1.0 }),
|
||||||
|
0.7,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dot_product(Vector { x: 1.0, y: 0.5 }, Vector { x: -0.2, y: -1.0 }),
|
||||||
|
-0.7,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_calculate_norm() {
|
||||||
|
assert_eq!(calculate_norm(&Vector { x: 0.5, y: 0.5 }), 0.5_f32.sqrt());
|
||||||
|
assert_eq!(calculate_norm(&Vector { x: 0.7, y: 0.3 }), 0.58_f32.sqrt());
|
||||||
|
assert_eq!(
|
||||||
|
calculate_norm(&Vector { x: -0.7, y: -0.3 }),
|
||||||
|
calculate_norm(&Vector { x: 0.7, y: 0.3 })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_normalize() {
|
||||||
|
let v1 = Vector { x: 0.5, y: 0.5 };
|
||||||
|
assert_eq!(calculate_norm(&normalize(&v1)).round(), 1_f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
69
src/main.rs
69
src/main.rs
@@ -1,69 +0,0 @@
|
|||||||
use image::{GrayImage, Luma};
|
|
||||||
use rayon::prelude::*;
|
|
||||||
use worldgen::generate_normalized_noise_map; // Import rayon for parallel processing
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Define parameters
|
|
||||||
let radius = 300;
|
|
||||||
let chunk_size = 16;
|
|
||||||
let num_chunks = 2 * radius + 1; // number of chunks per dimension (65 here)
|
|
||||||
let img_width = num_chunks * chunk_size;
|
|
||||||
let img_height = num_chunks * chunk_size;
|
|
||||||
|
|
||||||
// Generate all chunk coordinates from -radius to +radius
|
|
||||||
let chunk_coords: Vec<(i32, i32)> = (-radius..=radius)
|
|
||||||
.flat_map(|cx| (-radius..=radius).map(move |cz| (cx, cz)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Compute noise maps for each chunk in parallel using Rayon
|
|
||||||
let chunk_results: Vec<(i32, i32, [[f64; 16]; 16])> = chunk_coords
|
|
||||||
.into_par_iter()
|
|
||||||
.map(|(cx, cz)| {
|
|
||||||
let noise_map = generate_normalized_noise_map(42, cx, cz, 0.001);
|
|
||||||
(cx, cz, noise_map)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Create the big image with the appropriate dimensions
|
|
||||||
let mut big_img: GrayImage = GrayImage::new(img_width as u32, img_height as u32);
|
|
||||||
|
|
||||||
// Write each chunk's noise map into the global image at the corresponding position
|
|
||||||
for (cx, cz, noise_map) in chunk_results {
|
|
||||||
// Compute pixel offset: we shift de coordonnées de chunk pour obtenir des indices positifs
|
|
||||||
let offset_x = ((cx + radius) * chunk_size) as u32;
|
|
||||||
let offset_y = ((cz + radius) * chunk_size) as u32;
|
|
||||||
write_chunk_to_image(&mut big_img, offset_x, offset_y, noise_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the generated image to a file
|
|
||||||
big_img
|
|
||||||
.save("big_noise_map.png")
|
|
||||||
.expect("Failed to save image");
|
|
||||||
println!("Image saved as big_noise_map.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a 16x16 chunk noise map into the provided image at the specified offset.
|
|
||||||
/// Noise values are normalized from the range [-64, 324] to [0, 255].
|
|
||||||
fn write_chunk_to_image(
|
|
||||||
img: &mut GrayImage,
|
|
||||||
offset_x: u32,
|
|
||||||
offset_y: u32,
|
|
||||||
noise_map: [[f64; 16]; 16],
|
|
||||||
) {
|
|
||||||
let min_val = -64.0;
|
|
||||||
let max_val = 324.0;
|
|
||||||
let scale = 255.0 / (max_val - min_val);
|
|
||||||
|
|
||||||
// Iterate over each pixel in the 16x16 noise map
|
|
||||||
for (row_index, row) in noise_map.iter().enumerate() {
|
|
||||||
for (col_index, &value) in row.iter().enumerate() {
|
|
||||||
// Map noise value from [-64, 324] to [0, 255]
|
|
||||||
let pixel_value = (((value - min_val) * scale).round() as u8).min(255);
|
|
||||||
img.put_pixel(
|
|
||||||
offset_x + col_index as u32,
|
|
||||||
offset_y + row_index as u32,
|
|
||||||
Luma([pixel_value]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user