diff --git a/.vscode/launch.json b/.vscode/launch.json index 66e86d0..9a56cd6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "program": "${workspaceRoot}/target/debug/phos.exe", "args": [], "cwd": "${workspaceRoot}", - "preLaunchTask": "build", + "preLaunchTask": "Build", } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 34f3507..e4f59a0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,15 +1,17 @@ { - "version": "2.0.0", - "tasks":[ + "version": "2.0.0", + "tasks": [ { - "type":"cargo", - "command":"build", - "args":[], - "group": { - "kind": "build", - "isDefault": true - }, - "label":"build" + "type": "cargo", + "command": "", + "args": [ + "build" + ], + "problemMatcher": [ + "$rustc" + ], + "group": "build", + "label": "Build" } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index b17c9f5..51222ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2271,6 +2271,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "iyes_perf_ui" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49f5aa5866dadfdd274c45eddc0a94c84ad1ce0c02c27bcb33c34a20b961f9e" +dependencies = [ + "bevy", +] + [[package]] name = "jni" version = "0.21.1" @@ -2892,7 +2901,9 @@ version = "0.1.0" dependencies = [ "bevy", "bevy-inspector-egui", + "iyes_perf_ui", "noise 0.8.2", + "world_generation", ] [[package]] @@ -4274,6 +4285,7 @@ dependencies = [ name = "world_generation" version = "0.1.0" dependencies = [ + "bevy", "noise 0.9.0", ] diff --git a/engine/world_generation/Cargo.toml b/engine/world_generation/Cargo.toml index d57a4e4..1356c84 100644 --- a/engine/world_generation/Cargo.toml +++ b/engine/world_generation/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bevy = "0.13.1" noise = "0.9.0" diff --git a/engine/world_generation/src/data.rs b/engine/world_generation/src/data.rs deleted file mode 100644 index 4ae8383..0000000 --- a/engine/world_generation/src/data.rs +++ /dev/null @@ -1,26 +0,0 @@ -pub struct GenerationConfig { - pub noise_scale: f64, - pub sea_level: f64, - pub layers: Vec, -} -pub struct GeneratorLayer { - pub strength: f64, - pub min_value: f64, - pub base_roughness: f64, - pub roughness: f64, - pub persistence: f64, - pub is_rigid: bool, - pub weight: f64, - pub weight_multi: f64, - pub layers: usize, - pub first_layer_mask: bool, -} -pub struct Chunk { - pub points: Vec, - pub size: usize, -} -pub struct Map { - pub chunks: Vec, - pub height: usize, - pub width: usize, -} \ No newline at end of file diff --git a/engine/world_generation/src/heightmap.rs b/engine/world_generation/src/heightmap.rs index 0540cd6..0676b16 100644 --- a/engine/world_generation/src/heightmap.rs +++ b/engine/world_generation/src/heightmap.rs @@ -1,12 +1,8 @@ -mod data; -use data::*; +use crate::prelude::*; +use bevy::math::IVec2; +use noise::{NoiseFn, SuperSimplex}; -pub fn generate_heightmap( - height: usize, - width: usize, - cfg: &GenerationConfig, - seed: u32, -) -> Map { +pub fn generate_heightmap(height: usize, width: usize, cfg: &GenerationConfig, seed: u32) -> Map { let mut chunks: Vec = Vec::with_capacity(height * width); for z in 0..height { for x in 0..width { @@ -42,6 +38,7 @@ pub fn generate_chunk( return Chunk { points: result, size: size, + chunk_offset: IVec2::new(chunk_x as i32, chunk_z as i32), }; } @@ -108,4 +105,4 @@ fn sample_rigid(x: f64, z: f64, cfg: &GeneratorLayer, noise: &SuperSimplex) -> f } value -= cfg.min_value; return value * cfg.strength; -} \ No newline at end of file +} diff --git a/engine/world_generation/src/hex_utils.rs b/engine/world_generation/src/hex_utils.rs new file mode 100644 index 0000000..b72edcb --- /dev/null +++ b/engine/world_generation/src/hex_utils.rs @@ -0,0 +1,10 @@ +use bevy::prelude::*; + +pub const OUTER_RADIUS: f32 = 1.; +pub const INNER_RADIUS: f32 = OUTER_RADIUS * 0.866025404; + + +pub fn to_hex_pos(pos: Vec3) -> Vec3 { + let x = (pos.x + pos.z * 0.5 - (pos.z / 2.).floor()) * (INNER_RADIUS * 2.); + return Vec3::new(x, pos.y, pos.z * OUTER_RADIUS * 1.5); +} \ No newline at end of file diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index 54cdd4a..134f288 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -1,9 +1,38 @@ +pub mod prelude { + use bevy::math::IVec2; - use noise::{NoiseFn, SuperSimplex}; + pub struct GenerationConfig { + pub noise_scale: f64, + pub sea_level: f64, + pub layers: Vec, + } + pub struct GeneratorLayer { + pub strength: f64, + pub min_value: f64, + pub base_roughness: f64, + pub roughness: f64, + pub persistence: f64, + pub is_rigid: bool, + pub weight: f64, + pub weight_multi: f64, + pub layers: usize, + pub first_layer_mask: bool, + } + pub struct Chunk { + pub points: Vec, + pub size: usize, + pub chunk_offset: IVec2, + } + pub struct Map { + pub chunks: Vec, + pub height: usize, + pub width: usize, + } +} - - - +pub mod heightmap; +pub mod hex_utils; +pub mod mesh_generator; #[cfg(test)] mod tests { diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index 2f7ed09..e04f619 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -1,6 +1,73 @@ -mod data; -use data::Chunk; +use crate::{ + hex_utils::{to_hex_pos, INNER_RADIUS, OUTER_RADIUS}, + prelude::*, +}; +use bevy::{ + prelude::*, + render::{ + mesh::{Indices, PrimitiveTopology}, + render_asset::RenderAssetUsages, + }, +}; -pub fn generate_chunk_mesh(chunk: &Chunk){ +const HEX_CORNERS: [Vec3; 6] = [ + Vec3::new(0., 0., OUTER_RADIUS), + Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), + Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), + Vec3::new(0., 0., -OUTER_RADIUS), + Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS), + Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS), +]; -} \ No newline at end of file +pub fn generate_chunk_mesh(chunk: &Chunk) -> Mesh { + let vertex_count: usize = chunk.size * chunk.size; + let mut verts = Vec::with_capacity(vertex_count); + let mut uvs = Vec::with_capacity(vertex_count); + let mut normals = Vec::with_capacity(vertex_count); + let mut indices = Vec::with_capacity(vertex_count); + + for z in 0..chunk.size { + for x in 0..chunk.size { + let height = chunk.points[x + z * chunk.size]; + let off_pos = Vec3::new(x as f32, height, z as f32); + let grid_pos = to_hex_pos(off_pos); + create_tile(grid_pos, &mut verts, &mut uvs, &mut normals, &mut indices); + } + } + + let mesh = Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, verts) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + // .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_indices(Indices::U32(indices)) + .with_duplicated_vertices() + .with_computed_flat_normals(); + return mesh; +} + +//TODO: figure out texture index +fn create_tile( + pos: Vec3, + verts: &mut Vec, + uvs: &mut Vec, + normals: &mut Vec, + indices: &mut Vec, +) { + let idx = verts.len() as u32; + let center = Vec3::new(pos.x, 0., pos.z); + normals.push(Vec3::Y); + uvs.push(pos.xz()); + verts.push(pos); + for i in 0..6 { + let p = pos + HEX_CORNERS[i]; + verts.push(p); + uvs.push(p.xz()); + normals.push((p - center).normalize()); + indices.push(idx); + indices.push(idx + 1 + i as u32); + indices.push(idx + 1 + ((i as u32 + 1) % 6)); + } +} diff --git a/game/main/Cargo.toml b/game/main/Cargo.toml index fb51ddf..6d73939 100644 --- a/game/main/Cargo.toml +++ b/game/main/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bevy = "0.13.0" +bevy = "0.13.1" bevy-inspector-egui = "0.23.4" +iyes_perf_ui = "0.2.3" noise = "0.8.2" +world_generation ={path="../../engine/world_generation"} diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 7d938ef..00d8240 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -1,20 +1,33 @@ use bevy::{pbr::CascadeShadowConfig, prelude::*}; - +use iyes_perf_ui::prelude::*; +use world_generation::{ + heightmap::generate_heightmap, hex_utils::to_hex_pos, mesh_generator::generate_chunk_mesh, + prelude::*, +}; pub struct PhosGamePlugin; impl Plugin for PhosGamePlugin { - fn build(&self, app: &mut App) { - app.add_systems(Startup, init_game); - } + fn build(&self, app: &mut App) { + app.add_systems(Startup, init_game) + .add_systems(Startup, create_map); + app.add_plugins(bevy::diagnostic::FrameTimeDiagnosticsPlugin) + .add_plugins(bevy::diagnostic::EntityCountDiagnosticsPlugin) + .add_plugins(bevy::diagnostic::SystemInformationDiagnosticsPlugin) + .add_plugins(PerfUiPlugin); + } } fn init_game(mut commands: Commands) { + commands.spawn((Camera3dBundle { + transform: Transform::from_xyz(-200., 300., -200.) + .looking_at(Vec3::new(1000., 0., 1000.), Vec3::Y), + ..default() + },)); + commands.spawn(( - Camera3dBundle { - transform: Transform::from_xyz(0., 50., 0.) - .looking_at(Vec3::new(50., 0., 50.), Vec3::Y), - ..default() - }, + PerfUiRoot::default(), + PerfUiEntryFPS::default(), + PerfUiEntryClock::default(), )); commands.spawn(DirectionalLightBundle { @@ -30,3 +43,50 @@ fn init_game(mut commands: Commands) { ..default() }); } + +fn create_map( + mut commands: Commands, + mut materials: ResMut>, + mut meshes: ResMut>, +) { + let heightmap = generate_heightmap( + 32, + 32, + &GenerationConfig { + layers: vec![GeneratorLayer { + base_roughness: 2.14, + roughness: 0.87, + strength: 2.93, + min_value: -0.2, + persistence: 0.77, + is_rigid: false, + weight: 0., + weight_multi: 0., + layers: 4, + first_layer_mask: false, + }], + noise_scale: 250., + sea_level: 4., + }, + 1, + ); + + let debug_material = materials.add(StandardMaterial { + // base_color_texture: Some(images.add(uv_debug_texture())), + ..default() + }); + + for chunk in heightmap.chunks { + let mesh = generate_chunk_mesh(&chunk); + let pos = to_hex_pos( + Vec3::new(chunk.chunk_offset.x as f32, 0., chunk.chunk_offset.y as f32) + * chunk.size as f32, + ); + commands.spawn(PbrBundle { + mesh: meshes.add(mesh), + material: debug_material.clone(), + transform: Transform::from_translation(pos), + ..default() + }); + } +}