diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..413ecb6 --- /dev/null +++ b/build.rs @@ -0,0 +1,41 @@ +use std::process::Command; +use std::io::{self, Write}; +use std::path::Path; + +fn main() { + println!("cargo::rerun-if-changed=shaders/cube.frag"); + println!("cargo::rerun-if-changed=shaders/cube.geom"); + println!("cargo::rerun-if-changed=shaders/cube.vert"); + println!("cargo::rerun-if-changed=shaders/geo_cube.spv"); + println!("cargo::rerun-if-changed=shaders/frag_cube.spv"); + println!("cargo::rerun-if-changed=shaders/vert_cube.spv"); + + println!("cargo::rerun-if-changed=shaders/cuboid.frag"); + println!("cargo::rerun-if-changed=shaders/cuboid.geom"); + println!("cargo::rerun-if-changed=shaders/cuboid.vert"); + println!("cargo::rerun-if-changed=shaders/geo_cuboid.spv"); + println!("cargo::rerun-if-changed=shaders/frag_cuboid.spv"); + println!("cargo::rerun-if-changed=shaders/vert_cuboid.spv"); + + std::fs::remove_file("shaders/geo_cube.spv"); + std::fs::remove_file("shaders/frag_cube.spv"); + std::fs::remove_file("shaders/vert_cube.spv"); + std::fs::remove_file("shaders/geo_cuboid.spv"); + std::fs::remove_file("shaders/frag_cuboid.spv"); + std::fs::remove_file("shaders/vert_cuboid.spv"); + // probably need to check the os and have different versions + let mut command = Command::new("./shaders/compile.bat"); + let output = command.output().expect("Failed to execute command"); + println!("status: {}", output.status); + io::stdout().write_all(&output.stdout).unwrap(); + io::stderr().write_all(&output.stderr).unwrap(); + + assert!(output.status.success()); + + assert!(Path::new("shaders/geo_cube.spv").exists()); + assert!(Path::new("shaders/frag_cube.spv").exists()); + assert!(Path::new("shaders/vert_cube.spv").exists()); + assert!(Path::new("shaders/geo_cuboid.spv").exists()); + assert!(Path::new("shaders/frag_cuboid.spv").exists()); + assert!(Path::new("shaders/vert_cuboid.spv").exists()); +} \ No newline at end of file diff --git a/shaders/compile.bat b/shaders/compile.bat index 39e1fb0..27ac9c4 100644 --- a/shaders/compile.bat +++ b/shaders/compile.bat @@ -1,3 +1,7 @@ -C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.vert -o shaders/vert.spv -C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.frag -o shaders/frag.spv -C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/shader.geom -o shaders/geo.spv \ No newline at end of file +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cube.vert -o shaders/vert_cube.spv +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cube.frag -o shaders/frag_cube.spv +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cube.geom -o shaders/geo_cube.spv + +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cuboid.vert -o shaders/vert_cuboid.spv +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cuboid.frag -o shaders/frag_cuboid.spv +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cuboid.geom -o shaders/geo_cuboid.spv \ No newline at end of file diff --git a/shaders/shader.frag b/shaders/cube.frag similarity index 100% rename from shaders/shader.frag rename to shaders/cube.frag diff --git a/shaders/shader.geom b/shaders/cube.geom similarity index 100% rename from shaders/shader.geom rename to shaders/cube.geom diff --git a/shaders/shader.vert b/shaders/cube.vert similarity index 100% rename from shaders/shader.vert rename to shaders/cube.vert diff --git a/shaders/cuboid.frag b/shaders/cuboid.frag new file mode 100644 index 0000000..f53c648 --- /dev/null +++ b/shaders/cuboid.frag @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; + +layout(location = 0) out vec4 outColor; +layout(binding = 1) uniform sampler2D texSampler; + +void main() { + outColor = vec4(fragColor, 1); //texture(texSampler, fragTexCoord); +} \ No newline at end of file diff --git a/shaders/cuboid.geom b/shaders/cuboid.geom new file mode 100644 index 0000000..6419b62 --- /dev/null +++ b/shaders/cuboid.geom @@ -0,0 +1,181 @@ +#version 450 + +layout(points) in; +layout(triangle_strip, max_vertices=12) out; + +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 geom_rot; + mat4 view; + mat4 proj; + bool[16] use_geom_shader; +} ubo; + +layout(location = 0) in vec3 geoColor[]; +layout(location = 1) in vec2 geoTexCoord[]; +layout(location = 2) in vec3 geoSize[]; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoord; + +bool ignore_scalars = false; + +void main () { + mat4 geom_rotation = ubo.geom_rot; + //back + vec4 normal_back = geom_rotation * vec4(0, 0, -1, 0); + float scalar_back = dot(normal_back, vec4(1, 0, 0, 0)); + + if (scalar_back <= 0 || ignore_scalars){ + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } + + //front + vec4 normal_front = geom_rotation * vec4(0, 0, 1, 0); + float scalar_front = dot(normal_front, vec4(1, 0, 0, 0)); + if (scalar_front <= 0 || ignore_scalars) { + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } + //up + vec4 normal_up = geom_rotation * vec4(0, 1, 0, 0); + float scalar_up = dot(normal_up, vec4(1, 0, 0, 0)); + + if (scalar_up <= 0 || ignore_scalars) { + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } + //down + vec4 normal_down = geom_rotation * vec4(0, -1, 0, 0); + float scalar_down = dot(normal_down, vec4(1, 0, 0, 0)); + + if (scalar_down <= 0 || ignore_scalars) { + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } + //left + vec4 normal_left = geom_rotation * vec4(-1, 0, 0, 0); + float scalar_left = dot(normal_left, vec4(1, 0, 0, 0)); + + if (scalar_left <= 0 || ignore_scalars) { + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(-geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } + //right + vec4 normal_right = geom_rotation * vec4(1, 0, 0, 0); + float scalar_right = dot(normal_right, vec4(1, 0, 0, 0)); + + if (scalar_right <= 0 || ignore_scalars) { + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, -geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + + gl_Position = ubo.proj * ubo.view * (gl_in[0].gl_Position + geom_rotation * vec4(geoSize[0].x, geoSize[0].y, -geoSize[0].z, 0)); + fragColor = geoColor[0]; + fragTexCoord = geoTexCoord[0]; + EmitVertex(); + EndPrimitive(); + } +} \ No newline at end of file diff --git a/shaders/cuboid.vert b/shaders/cuboid.vert new file mode 100644 index 0000000..99c6ccf --- /dev/null +++ b/shaders/cuboid.vert @@ -0,0 +1,30 @@ +#version 450 + +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 geom_rot; + mat4 view; + mat4 proj; + bool[16] use_geom_shader; +} ubo; + + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTexCoord; +layout(location = 3) in vec3 inSize; + +layout(location = 0) out vec3 geoColor; +layout(location = 1) out vec2 geoTexCoord; +layout(location = 2) out vec3 geoSize; + +void main() { + if (ubo.use_geom_shader[0]) { + gl_Position = ubo.geom_rot * ubo.model * vec4(inPosition, 1.0); + } else { + gl_Position = ubo.proj * ubo.view * ubo.geom_rot * ubo.model * vec4(inPosition, 1.0); + } + geoColor = inColor; + geoTexCoord = inTexCoord; + geoSize = inSize; +} \ No newline at end of file diff --git a/shaders/frag.spv b/shaders/frag_cube.spv similarity index 100% rename from shaders/frag.spv rename to shaders/frag_cube.spv diff --git a/shaders/frag_cuboid.spv b/shaders/frag_cuboid.spv new file mode 100644 index 0000000..1ebe140 Binary files /dev/null and b/shaders/frag_cuboid.spv differ diff --git a/shaders/geo.spv b/shaders/geo_cube.spv similarity index 100% rename from shaders/geo.spv rename to shaders/geo_cube.spv diff --git a/shaders/geo_cuboid.spv b/shaders/geo_cuboid.spv new file mode 100644 index 0000000..8e45c97 Binary files /dev/null and b/shaders/geo_cuboid.spv differ diff --git a/shaders/vert.spv b/shaders/vert_cube.spv similarity index 100% rename from shaders/vert.spv rename to shaders/vert_cube.spv diff --git a/shaders/vert_cuboid.spv b/shaders/vert_cuboid.spv new file mode 100644 index 0000000..e4f3503 Binary files /dev/null and b/shaders/vert_cuboid.spv differ diff --git a/src/main.rs b/src/main.rs index c747232..be21161 100644 --- a/src/main.rs +++ b/src/main.rs @@ -642,9 +642,9 @@ unsafe fn create_logical_device( } unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Result<()> { - let vert = include_bytes!("../shaders/vert.spv"); - let geo = include_bytes!("../shaders/geo.spv"); - let frag = include_bytes!("../shaders/frag.spv"); + let vert = include_bytes!("../shaders/vert_cube.spv"); + let geo = include_bytes!("../shaders/geo_cube.spv"); + let frag = include_bytes!("../shaders/frag_cube.spv"); let vert_shader_module = create_shader_module(device, &vert[..])?; let geo_shader_module = create_shader_module(device, &geo[..])?; diff --git a/src/primitives.rs b/src/primitives.rs deleted file mode 100644 index 887bbb1..0000000 --- a/src/primitives.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod cube; \ No newline at end of file diff --git a/src/primitives/cube.rs b/src/primitives/cube.rs index 53afd86..f7fba65 100644 --- a/src/primitives/cube.rs +++ b/src/primitives/cube.rs @@ -2,6 +2,7 @@ use vulkanalia::prelude::v1_0::*; use cgmath::vec3; use crate::vertex; use crate::scene::Scene; +use crate::primitives::drawable::Drawable; #[derive(Clone, Debug)] pub struct Cube{ @@ -10,8 +11,8 @@ pub struct Cube{ pub tex_coord: vertex::Vec2 } -impl Cube { - pub fn draw(& self, topology: &vk::PrimitiveTopology, start_index: usize, scene: &mut Scene) { +impl Drawable for Cube { + fn draw(& self, topology: &vk::PrimitiveTopology, start_index: usize, scene: &mut Scene) { if *topology == vk::PrimitiveTopology::TRIANGLE_LIST { // 0 top left far scene.vertices.push(vertex::Vertex::new( diff --git a/src/primitives/drawable.rs b/src/primitives/drawable.rs new file mode 100644 index 0000000..cb8cfae --- /dev/null +++ b/src/primitives/drawable.rs @@ -0,0 +1,6 @@ +use vulkanalia::prelude::v1_0::*; +use crate::scene::Scene; + +pub trait Drawable { + fn draw(& self, topology: &vk::PrimitiveTopology, start_index: usize, scene: &mut Scene); +} \ No newline at end of file diff --git a/src/primitives/mod.rs b/src/primitives/mod.rs new file mode 100644 index 0000000..7b1f5d3 --- /dev/null +++ b/src/primitives/mod.rs @@ -0,0 +1,3 @@ +pub mod cube; +pub mod rec_cuboid; +pub mod drawable; \ No newline at end of file diff --git a/src/primitives/rec_cuboid.rs b/src/primitives/rec_cuboid.rs new file mode 100644 index 0000000..ffdd4e5 --- /dev/null +++ b/src/primitives/rec_cuboid.rs @@ -0,0 +1,133 @@ +use vulkanalia::prelude::v1_0::*; +use cgmath::vec3; +use crate::vertex; +use crate::scene::Scene; +use crate::primitives::drawable::Drawable; + +#[derive(Clone, Debug)] +pub struct Cuboid{ + pub pos: vertex::Vec3, + pub color: vertex::Vec3, + pub tex_coord: vertex::Vec2, + pub size: vertex::Vec3, +} + +impl Drawable for Cuboid { + fn draw(& self, topology: &vk::PrimitiveTopology, start_index: usize, scene: &mut Scene) { + if *topology == vk::PrimitiveTopology::TRIANGLE_LIST { + // 0 top left far + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 - 0.5 * self.size.x, self.pos.y as f32 + 0.5 * self.size.y, self.pos.z as f32 + 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 1 top right far + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 + 0.5 * self.size.x, self.pos.y as f32 + 0.5 * self.size.y, self.pos.z as f32 + 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 2 top left near + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 - 0.5 * self.size.x, self.pos.y as f32 - 0.5 * self.size.y, self.pos.z as f32 + 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 3 top right near + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 + 0.5 * self.size.x, self.pos.y as f32 - 0.5 * self.size.y, self.pos.z as f32 + 0.5 * self.size.z), + self.color, + self.tex_coord + )); + + // 4 bottom left far + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 - 0.5 * self.size.x, self.pos.y as f32 + 0.5 * self.size.y, self.pos.z as f32 - 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 5 bottom right far + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 + 0.5 * self.size.x, self.pos.y as f32 + 0.5 * self.size.y, self.pos.z as f32 - 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 6 bottom left near + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 - 0.5 * self.size.x, self.pos.y as f32 - 0.5 * self.size.y, self.pos.z as f32 - 0.5 * self.size.z), + self.color, + self.tex_coord + )); + // 7 bottom right near + scene.vertices.push(vertex::Vertex::new( + vec3(self.pos.x as f32 + 0.5 * self.size.x, self.pos.y as f32 - 0.5 * self.size.y, self.pos.z as f32 - 0.5 * self.size.z), + self.color, + self.tex_coord + )); + + + // top + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 0); + scene.indices.push(start_index as u32 + 2); + + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 1); + scene.indices.push(start_index as u32 + 0); + + // bottom + scene.indices.push(start_index as u32 + 6); + scene.indices.push(start_index as u32 + 4); + scene.indices.push(start_index as u32 + 7); + + scene.indices.push(start_index as u32 + 4); + scene.indices.push(start_index as u32 + 5); + scene.indices.push(start_index as u32 + 7); + + // left + scene.indices.push(start_index as u32 + 0); + scene.indices.push(start_index as u32 + 4); + scene.indices.push(start_index as u32 + 2); + + scene.indices.push(start_index as u32 + 6); + scene.indices.push(start_index as u32 + 2); + scene.indices.push(start_index as u32 + 4); + + // right + scene.indices.push(start_index as u32 + 1); + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 5); + + scene.indices.push(start_index as u32 + 5); + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 7); + + // near + scene.indices.push(start_index as u32 + 6); + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 2); + + scene.indices.push(start_index as u32 + 3); + scene.indices.push(start_index as u32 + 6); + scene.indices.push(start_index as u32 + 7); + + // far + scene.indices.push(start_index as u32 + 0); + scene.indices.push(start_index as u32 + 1); + scene.indices.push(start_index as u32 + 4); + + scene.indices.push(start_index as u32 + 5); + scene.indices.push(start_index as u32 + 4); + scene.indices.push(start_index as u32 + 1); + } + if *topology == vk::PrimitiveTopology::POINT_LIST { + scene.sized_vertices.push(vertex::SizedVertex::new( + self.pos, + self.color, + self.tex_coord, + self.size, + )); + scene.indices.push(start_index as u32); + } + } +} \ No newline at end of file diff --git a/src/scene.rs b/src/scene.rs index d77c898..032e299 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -1,24 +1,33 @@ +use anyhow::Ok; use vulkanalia::prelude::v1_0::*; use anyhow::Result; -use cgmath::{vec2, vec3}; +use cgmath::{vec2, vec3, Vector3}; +use std::cell::RefCell; use std::collections::HashMap; +use std::rc::Rc; use rustc_hash::FxHashMap; use crate::app_data::AppData; use crate::buffer; +use crate::primitives::rec_cuboid::Cuboid; use crate::vertex; use crate::primitives::cube::Cube; +use crate::primitives::drawable::Drawable; extern crate rand; use rand::Rng; -const CHUNK_SIZE: usize = 500; +const CHUNK_SIZE_EXPONENT: u32 = 10; +const CHUNK_SIZE: usize = (2 as usize).pow(CHUNK_SIZE_EXPONENT); +const MAX_TREE_DEPTH: usize = 8; +const MIN_CHUNK_SIZE: usize = CHUNK_SIZE / (2 as usize).pow(MAX_TREE_DEPTH as u32); #[derive(Clone, Debug, Default)] pub struct Scene { pub vertices: Vec, + pub sized_vertices: Vec, pub indices: Vec, pub vertex_buffer: vk::Buffer, @@ -34,7 +43,7 @@ impl Scene { let grid_size = CHUNK_SIZE as i32; // todo store the chunks somewhere (or only use them as intermediary for neighbouthood calculation idc) - let mut chunks = vec![Chunk::create()?]; + let mut oct_tree = OctTree::create(CHUNK_SIZE)?; //todo use the 14 vertice box method. Not using geometry shaders seems to be faster... make this a setting? // have cube elements with a method asking for vertices, while giving a primitive type -> method for preferred primitive type as well as one collecting all primitives @@ -46,17 +55,25 @@ impl Scene { color: vec3(shade, 1.0, shade), tex_coord: vec2(0.0, 0.0) }; - chunks[0].set_cube(cube); + + oct_tree.set_cube(cube.clone()); } } - let chunk = &chunks[0]; - let chunk_iter = ChunkIter::create(chunk)?; - for item in chunk_iter { + let oct_tree_iter = OctTreeIter::create(&oct_tree)?; + for item in oct_tree_iter { let index = self.vertices.len(); match item { Some(cube) => { + /*let cuboid = Cuboid { + pos: cube.pos, + color: cube.color, + tex_coord: cube.tex_coord, + size: Vector3 {x: 1.0, y: 1.0, z: 1.0}, + }; + cuboid.draw(&data.topology, index, self);*/ cube.draw(&data.topology, index, self); + } None => {} } @@ -79,16 +96,47 @@ impl Scene { } #[derive(Clone, Debug)] -struct Chunk { - //todo change to hashmap? - blocks: HashMap, Cube, rustc_hash::FxBuildHasher>, +struct OctTree { + pub child_XYZ: Option>>, + pub child_xYZ: Option>>, + pub child_xyZ: Option>>, + pub child_XyZ: Option>>, + pub child_XYz: Option>>, + pub child_xYz: Option>>, + pub child_xyz: Option>>, + pub child_Xyz: Option>>, + + pub blocks: Vec>, + + size: usize, } -impl Chunk { - pub fn create() -> Result { - let mut map: HashMap, Cube, rustc_hash::FxBuildHasher> = FxHashMap::default(); +impl OctTree { + pub fn create(size: usize) -> Result { + let mut blocks: Vec> = vec![]; + if size == MIN_CHUNK_SIZE { + for _ in 0..MIN_CHUNK_SIZE { + for _ in 0..MIN_CHUNK_SIZE { + for _ in 0..MIN_CHUNK_SIZE { + blocks.push(None); + } + } + } + } + Ok(Self { - blocks: map + child_XYZ: None, + child_xYZ: None, + child_xyZ: None, + child_XyZ: None, + child_XYz: None, + child_xYz: None, + child_xyz: None, + child_Xyz: None, + + blocks: blocks, + + size, }) } @@ -96,62 +144,335 @@ impl Chunk { let x = cube.pos.x as usize; let y = cube.pos.y as usize; let z = cube.pos.z as usize; - assert!(x < CHUNK_SIZE, "x value out of range!"); - assert!(y < CHUNK_SIZE, "y value out of range!"); - assert!(z < CHUNK_SIZE, "z value out of range!"); - self.blocks.insert(vec3(x as u32, y as u32, z as u32), cube); + assert!(x < self.size, "x value out of range!"); + assert!(y < self.size, "y value out of range!"); + assert!(z < self.size, "z value out of range!"); + self.set_cube_internal(cube, x, y, z); + } + + fn set_cube_internal(&mut self, cube: Cube, x: usize, y: usize, z: usize) { + if self.size > MIN_CHUNK_SIZE { + let mid_point = self.size / 2; + if x >= mid_point { + if y >= mid_point { + if z >= mid_point { + match &self.child_XYZ { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x - mid_point, y - mid_point, z - mid_point); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x - mid_point, y - mid_point, z - mid_point); + self.child_XYZ = Some(Rc::new(RefCell::new(child))); + } + } + } + else { + match &self.child_XYz { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x - mid_point, y - mid_point, z); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x - mid_point, y - mid_point, z); + self.child_XYz = Some(Rc::new(RefCell::new(child))); + } + } + } + } + else { + if z >= mid_point { + match &self.child_XyZ { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x - mid_point, y, z - mid_point); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x - mid_point, y, z - mid_point); + self.child_XyZ = Some(Rc::new(RefCell::new(child))); + } + } + } + else { + match &self.child_Xyz { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x - mid_point, y, z); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x - mid_point, y, z); + self.child_Xyz = Some(Rc::new(RefCell::new(child))); + } + } + } + } + } + else { + if y >= mid_point { + if z >= mid_point { + match &self.child_xYZ { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x, y - mid_point, z - mid_point); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x, y - mid_point, z - mid_point); + self.child_xYZ = Some(Rc::new(RefCell::new(child))); + } + } + } + else { + match &self.child_xYz { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x, y - mid_point, z); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x, y - mid_point, z); + self.child_xYz = Some(Rc::new(RefCell::new(child))); + } + } + } + } + else { + if z >= mid_point { + match &self.child_xyZ { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x, y, z - mid_point); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x, y, z - mid_point); + self.child_xyZ = Some(Rc::new(RefCell::new(child))); + } + } + } + else { + match &self.child_xyz { + Some(child) => { + child.borrow_mut().set_cube_internal(cube, x, y, z); + }, + None => { + let mut child = OctTree::create(self.size / 2).unwrap(); + child.set_cube_internal(cube, x, y, z); + self.child_xyz = Some(Rc::new(RefCell::new(child))); + } + } + } + } + } + } + else { + self.blocks[z * MIN_CHUNK_SIZE * MIN_CHUNK_SIZE + y * MIN_CHUNK_SIZE + x] = Some(cube); + } } pub fn clear_cube(&mut self, x: usize, y: usize, z: usize) { - assert!(x < CHUNK_SIZE, "x value out of range!"); - assert!(y < CHUNK_SIZE, "y value out of range!"); - assert!(z < CHUNK_SIZE, "z value out of range!"); - self.blocks.remove(&vec3(x as u32, y as u32, z as u32)); + assert!(x < self.size, "x value out of range!"); + assert!(y < self.size, "y value out of range!"); + assert!(z < self.size, "z value out of range!"); + //self.blocks.remove(&vec3(x as u32, y as u32, z as u32)); + + self.clear_cube_internal(x, y, z) } + fn clear_cube_internal(&mut self, x: usize, y: usize, z: usize) { + if self.size > MIN_CHUNK_SIZE { + let mid_point = self.size / 2; + if x >= mid_point { + if y >= mid_point { + if z >= mid_point { + match &self.child_XYZ { + Some(child) => { + child.borrow_mut().clear_cube_internal(x - mid_point, y - mid_point, z - mid_point); + }, + None => {} + } + } + else { + match &self.child_XYz { + Some(child) => { + child.borrow_mut().clear_cube_internal(x - mid_point, y - mid_point, z); + }, + None => {} + } + } + } + else { + if z >= mid_point { + match &self.child_XyZ { + Some(child) => { + child.borrow_mut().clear_cube_internal(x - mid_point, y, z - mid_point); + }, + None => {} + } + } + else { + match &self.child_Xyz { + Some(child) => { + child.borrow_mut().clear_cube_internal(x - mid_point, y, z); + }, + None => {} + } + } + } + } + else { + if y >= mid_point { + if z >= mid_point { + match &self.child_xYZ { + Some(child) => { + child.borrow_mut().clear_cube_internal(x, y - mid_point, z - mid_point); + }, + None => {} + } + } + else { + match &self.child_xYz { + Some(child) => { + child.borrow_mut().clear_cube_internal(x, y - mid_point, z); + }, + None => {} + } + } + } + else { + if z >= mid_point { + match &self.child_xyZ { + Some(child) => { + child.borrow_mut().clear_cube_internal(x, y, z - mid_point); + }, + None => {} + } + } + else { + match &self.child_xyz { + Some(child) => { + child.borrow_mut().clear_cube_internal(x, y, z); + }, + None => {} + } + } + } + } + } + else { + self.blocks[z * MIN_CHUNK_SIZE * MIN_CHUNK_SIZE + y * MIN_CHUNK_SIZE + x] = None; + } + } } -struct ChunkIter<'a> { +struct OctTreeIter<'a> { iter_x: usize, iter_y: usize, iter_z: usize, - chunk: &'a Chunk + todo: Vec>>, + chunk: &'a OctTree } -impl<'a> ChunkIter<'a> { - pub fn create(chunk: &'a Chunk) -> Result { - - Ok(Self { +impl<'a> OctTreeIter<'a> { + pub fn create(chunk: &'a OctTree) -> Result { + let mut out = Self { iter_x: 0, iter_y: 0, iter_z: 0, + todo: vec![], chunk - }) + }; + out.add_todo(&chunk); + Ok(out) + } + + fn add_todo(&mut self, oct_tree: &OctTree) { + match &oct_tree.child_XYZ { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_xYZ { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_xyZ { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_XyZ { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_XYz { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_xYz { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_xyz { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; + match &oct_tree.child_Xyz { + Some(child) => { + self.todo.push(child.clone()); + }, + None => {}, + }; } } -impl<'a> Iterator for ChunkIter<'a> { - type Item = Option<&'a Cube>; +impl<'a> Iterator for OctTreeIter<'a> { + type Item = Option; fn next(&mut self) -> Option { - if self.iter_x < CHUNK_SIZE && self.iter_y < CHUNK_SIZE && self.iter_z < CHUNK_SIZE { - let result = self.chunk.blocks.get(&vec3(self.iter_x as u32, self.iter_y as u32, self.iter_z as u32)); + if self.todo.len() != 0 { + while self.todo.last().unwrap().borrow().blocks.len() == 0 { + let oct_tree = self.todo.pop().unwrap(); + self.add_todo(&oct_tree.borrow()); + } - self.iter_x += 1; - if self.iter_x >= CHUNK_SIZE { - self.iter_x = 0; - self.iter_y += 1; + if self.iter_x < MIN_CHUNK_SIZE && self.iter_y < MIN_CHUNK_SIZE && self.iter_z < MIN_CHUNK_SIZE { + let result = self.todo.last().unwrap().borrow().blocks[self.iter_x + self.iter_y * MIN_CHUNK_SIZE + self.iter_z * MIN_CHUNK_SIZE * MIN_CHUNK_SIZE].clone(); + + self.iter_x += 1; + if self.iter_x >= MIN_CHUNK_SIZE { + self.iter_x = 0; + self.iter_y += 1; + } + if self.iter_y >= MIN_CHUNK_SIZE { + self.iter_y = 0; + self.iter_z += 1; + } + + if self.iter_z == MIN_CHUNK_SIZE { + self.todo.pop(); + self.iter_x = 0; + self.iter_y = 0; + self.iter_z = 0; + } + + return Some(result) } - if self.iter_y >= CHUNK_SIZE { - self.iter_y = 0; - self.iter_z += 1; - } - return Some(result.clone()) } + self.iter_x = 0; self.iter_y = 0; self.iter_z = 0; + self.add_todo(&self.chunk); None } -} - +} \ No newline at end of file diff --git a/src/vertex.rs b/src/vertex.rs index 78c8465..6be4883 100644 --- a/src/vertex.rs +++ b/src/vertex.rs @@ -76,4 +76,75 @@ impl Hash for Vertex { self.tex_coord[0].to_bits().hash(state); self.tex_coord[1].to_bits().hash(state); } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct SizedVertex { + pub pos: Vec3, + pub color: Vec3, + pub tex_coord: Vec2, + pub size: Vec3, +} + +impl SizedVertex { + pub const fn new(pos: Vec3, color: Vec3, tex_coord: Vec2, size: Vec3) -> Self { + Self { pos, color, tex_coord, size } + } + + pub fn binding_description() -> vk::VertexInputBindingDescription { + vk::VertexInputBindingDescription::builder() + .binding(0) + .stride(size_of::() as u32) + .input_rate(vk::VertexInputRate::VERTEX) + .build() + } + + pub fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] { + let pos = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(0) + .format(vk::Format::R32G32B32_SFLOAT) + .offset(0) + .build(); + + let color = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(1) + .format(vk::Format::R32G32B32_SFLOAT) + .offset(size_of::() as u32) + .build(); + + let tex_coord = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(2) + .format(vk::Format::R32G32_SFLOAT) + .offset((size_of::() + size_of::()) as u32) + .build(); + [pos, color, tex_coord] + } +} + + +impl PartialEq for SizedVertex { + fn eq(&self, other: &Self) -> bool { + self.pos == other.pos + && self.color == other.color + && self.tex_coord == other.tex_coord + } +} + +impl Eq for SizedVertex {} + +impl Hash for SizedVertex { + fn hash(&self, state: &mut H) { + self.pos[0].to_bits().hash(state); + self.pos[1].to_bits().hash(state); + self.pos[2].to_bits().hash(state); + self.color[0].to_bits().hash(state); + self.color[1].to_bits().hash(state); + self.color[2].to_bits().hash(state); + self.tex_coord[0].to_bits().hash(state); + self.tex_coord[1].to_bits().hash(state); + } } \ No newline at end of file