Implemented Octrees, refactored heap allocations for FreeLists and some spring-cleaning. Builds and runs, octrees fail to form correctly and reinsertion steps are unimplemented.
This commit is contained in:
parent
cf965d489c
commit
905d05bc39
17 changed files with 918 additions and 630 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
target
|
target
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
Cargo.lock
|
||||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Ignored default folder with query files
|
|
||||||
/queries/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
6
.idea/Pool.iml
generated
6
.idea/Pool.iml
generated
|
|
@ -3,13 +3,7 @@
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/stupid_display/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/mars/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/lang/src" isTestSource="false" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/stupid_display/target" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/src/mars/target" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/lang/target" />
|
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
|
|
@ -1,5 +0,0 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
8
.idea/dictionaries/project.xml
generated
8
.idea/dictionaries/project.xml
generated
|
|
@ -1,8 +0,0 @@
|
||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="project">
|
|
||||||
<words>
|
|
||||||
<w>forloop</w>
|
|
||||||
<w>vmcase</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,14 +1,18 @@
|
||||||
[package]
|
[package]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
name = "game"
|
name = "pool"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
big_ids = []
|
||||||
|
check_ids = []
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true
|
strip = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "game"
|
name = "pool"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
@ -17,7 +21,7 @@ anyhow = "1.0"
|
||||||
winit = { version = "0.30", features = ["android-native-activity"] }
|
winit = { version = "0.30", features = ["android-native-activity"] }
|
||||||
env_logger = "0.11.10"
|
env_logger = "0.11.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
wgpu = "29.0.3"
|
wgpu = "29.0.4"
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
glam = { version = "0.33.3", features = [ "bytemuck" ] }
|
glam = { version = "0.33.3", features = [ "bytemuck" ] }
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
|
|
@ -27,7 +31,7 @@ mars = { path = "../Mars" }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
wgpu = { version = "29.0.3", features = ["webgl"]}
|
wgpu = { version = "30.0.1", features = ["webgl"]}
|
||||||
wasm-bindgen = "0.2.121"
|
wasm-bindgen = "0.2.121"
|
||||||
wasm-bindgen-futures = "0.4.71"
|
wasm-bindgen-futures = "0.4.71"
|
||||||
console_log = "1.0.0"
|
console_log = "1.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
_Pool. Hop in, the water's warm._
|
_Pool. Hop in, the water's warm._
|
||||||
|
|
||||||
Pool is a lightweight web-enabled multipurpose engine for UI apps and multiplayer games with physics designed to push the boundaries of what defines a contemporary user experience.
|
Pool is a lightweight web-enabled multipurpose engine for UI apps and multiplayer games with physics.
|
||||||
|
|
||||||
Taking inspiration from the Roblox game engine, Pool ships with its own scripting language, Mars, and shares a similar instance-service model.
|
Taking inspiration from the Roblox game engine, Pool ships with its own scripting language, Mars, and shares a similar instance-service model.
|
||||||
|
|
||||||
|
|
|
||||||
126
src/app.rs
126
src/app.rs
|
|
@ -1,8 +1,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
|
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
|
||||||
use crate::render::Renderer;
|
use crate::render::{ModelData, Renderer};
|
||||||
use crate::world::{SimpleObject, World};
|
use crate::world::{World, ObjectData, OctreeDebug};
|
||||||
use glam::{Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4};
|
use glam::{Affine3, Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
@ -16,6 +16,8 @@ use winit::{
|
||||||
keyboard::{KeyCode, PhysicalKey},
|
keyboard::{KeyCode, PhysicalKey},
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
|
use crate::list::Id;
|
||||||
|
use crate::state;
|
||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
buttons: HashMap<MouseButton, bool>,
|
buttons: HashMap<MouseButton, bool>,
|
||||||
|
|
@ -34,68 +36,66 @@ impl Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
world: World,
|
state: state::State,
|
||||||
|
world: Id<World>,
|
||||||
|
debug: OctreeDebug,
|
||||||
|
debug_model: ModelData,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
window: Arc<Window>,
|
window: Arc<Window>,
|
||||||
clients: Vec<SimpleObject>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BLOCKS: i32 = 4;
|
const BLOCKS: i32 = 2;
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
// We don't need this to be async right now,
|
// We don't need this to be async right now,
|
||||||
// but we will in the next tutorial
|
// but we will in the next tutorial
|
||||||
pub async fn new(window: Arc<Window>) -> Result<AppState, Box<dyn std::error::Error>> {
|
pub async fn new(window: Arc<Window>) -> Result<AppState, Box<dyn std::error::Error>> {
|
||||||
let mut world = World::new();
|
let mut state = state::State::new();
|
||||||
world.add_renderer(Renderer::new(&window).await?);
|
let (world,debug,debug_model) = {
|
||||||
let mut clients = Vec::new();
|
let mut world = state.worlds.make(World::new());
|
||||||
|
state.renderer = Some(Renderer::new(&window).await?);
|
||||||
|
let renderer = state.renderer.as_mut().unwrap();
|
||||||
|
let debug_file = renderer.load_from_gltf(include_bytes!("assets/debug.glb"));
|
||||||
|
let debug_model = debug_file.first_object().unwrap().model.unwrap();
|
||||||
{
|
{
|
||||||
let file = world
|
let file = renderer.load_from_gltf(include_bytes!("assets/sphere.glb"));
|
||||||
.renderer
|
let mut block = file.first_object().unwrap();
|
||||||
.as_mut()
|
let skybox = renderer.load_texture_from_bytes(
|
||||||
.unwrap()
|
|
||||||
.load_from_gltf(include_bytes!("assets/sphere.glb"));
|
|
||||||
let block = file.first_object().unwrap();
|
|
||||||
let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes(
|
|
||||||
include_bytes!("assets/skybox2.png"),
|
include_bytes!("assets/skybox2.png"),
|
||||||
Some(image::ImageFormat::Png),
|
Some(image::ImageFormat::Png),
|
||||||
);
|
);
|
||||||
world.renderer().set_skybox(skybox);
|
renderer.set_skybox(skybox);
|
||||||
let color = world
|
let color = renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png"), None);
|
||||||
.renderer()
|
let normal = renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"), None);
|
||||||
.load_texture_from_bytes(include_bytes!("assets/plank/color.png"), None);
|
let roughness = renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"), None);
|
||||||
let normal = world
|
let mat = renderer.new_material(&color, &normal, &roughness);
|
||||||
.renderer()
|
block.model.as_mut().unwrap().material = mat;
|
||||||
.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"), None);
|
for x in -BLOCKS..=BLOCKS {
|
||||||
let roughness = world
|
for y in -BLOCKS..=BLOCKS {
|
||||||
.renderer()
|
let id = world.add_object(state.objects.make(block.clone()));
|
||||||
.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"), None);
|
let block = state.objects.get(&id);
|
||||||
let mat = world.renderer().new_material(&color, &normal, &roughness);
|
|
||||||
block.0.borrow_mut().model.as_mut().unwrap().material = mat;
|
|
||||||
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();
|
block.affine = Affine3::from_translation(
|
||||||
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
|
|
||||||
Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0),
|
Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0),
|
||||||
)
|
);
|
||||||
* Mat4::from_rotation_z((x * y) as f32 / 1.23);
|
block.model.as_mut().unwrap().instance.color = Vec4::new(
|
||||||
model.model.as_mut().unwrap().instance.color = Vec4::new(
|
|
||||||
0.3,
|
0.3,
|
||||||
(x + BLOCKS) as f32 / BLOCKS as f32,
|
(x + BLOCKS) as f32 / BLOCKS as f32,
|
||||||
(y + BLOCKS) as f32 / BLOCKS as f32,
|
(y + BLOCKS) as f32 / BLOCKS as f32,
|
||||||
1.0,
|
1.0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
clients.push(block)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let debug = OctreeDebug::new();
|
||||||
|
(world.id,debug,debug_model)
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
state,
|
||||||
world,
|
world,
|
||||||
clients,
|
debug,
|
||||||
|
debug_model,
|
||||||
controller: Controller::new(),
|
controller: Controller::new(),
|
||||||
window,
|
window,
|
||||||
})
|
})
|
||||||
|
|
@ -108,7 +108,7 @@ impl AppState {
|
||||||
|
|
||||||
pub fn resize(&mut self, width: u32, height: u32) {
|
pub fn resize(&mut self, width: u32, height: u32) {
|
||||||
if width > 0 && height > 0 {
|
if width > 0 && height > 0 {
|
||||||
self.world.renderer.as_mut().unwrap().resize(width, height);
|
self.state.renderer.as_mut().unwrap().resize(width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ impl AppState {
|
||||||
(KeyCode::Escape, true) => event_loop.exit(),
|
(KeyCode::Escape, true) => event_loop.exit(),
|
||||||
(KeyCode::Space, true) => {}
|
(KeyCode::Space, true) => {}
|
||||||
(KeyCode::KeyR, true) => {
|
(KeyCode::KeyR, true) => {
|
||||||
self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY
|
self.state.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ impl AppState {
|
||||||
|
|
||||||
fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) {
|
fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) {
|
||||||
if let Some(true) = self.controller.buttons.get(&MouseButton::Right) {
|
if let Some(true) = self.controller.buttons.get(&MouseButton::Right) {
|
||||||
self.world.renderer.as_mut().unwrap().eye.rotate(
|
self.state.renderer.as_mut().unwrap().eye.rotate(
|
||||||
position.x as f32 - self.controller.mouse.x,
|
position.x as f32 - self.controller.mouse.x,
|
||||||
position.y as f32 - self.controller.mouse.y,
|
position.y as f32 - self.controller.mouse.y,
|
||||||
);
|
);
|
||||||
|
|
@ -182,6 +182,8 @@ impl ApplicationHandler<AppState> for App {
|
||||||
|
|
||||||
let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
|
let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
|
||||||
|
|
||||||
|
window.set_title("Pool");
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
// If we are not on web we can use pollster to
|
// If we are not on web we can use pollster to
|
||||||
|
|
@ -238,15 +240,14 @@ impl ApplicationHandler<AppState> for App {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::Resized(size) => state.resize(size.width, size.height),
|
WindowEvent::Resized(size) => state.resize(size.width, size.height),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
|
use std::time::Instant;
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
state.update();
|
state.update();
|
||||||
let mut movement = Vec3::new(0.0, 0.0, 0.0);
|
let mut movement = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
let pressed = |keycode: KeyCode| {
|
let pressed = |keycode: KeyCode| {
|
||||||
if let Some(true) = state.controller.keys.get(&keycode) {
|
matches!(state.controller.keys.get(&keycode), Some(true))
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if pressed(KeyCode::KeyA) {
|
if pressed(KeyCode::KeyA) {
|
||||||
|
|
@ -267,15 +268,12 @@ impl ApplicationHandler<AppState> for App {
|
||||||
if pressed(KeyCode::KeyQ) {
|
if pressed(KeyCode::KeyQ) {
|
||||||
movement.y -= 1.0;
|
movement.y -= 1.0;
|
||||||
}
|
}
|
||||||
|
let world = state.state.worlds.get(&state.world);
|
||||||
state
|
state.debug.set(&mut state.state.objects, world, Some(state.debug_model.clone()));
|
||||||
.world
|
state.debug.register(&mut state.state.objects,state.state.renderer.as_mut().unwrap());
|
||||||
.renderer
|
world.step(&mut state.state.renderer, &mut state.state.objects, &mut state.state.lights);
|
||||||
.as_mut()
|
state.state.renderer.as_mut().unwrap().eye.control(movement * 0.1);
|
||||||
.unwrap()
|
match state.state.renderer.as_mut().unwrap().render(&state.window,&mut state.state.objects) {
|
||||||
.eye
|
|
||||||
.control(movement * 0.1);
|
|
||||||
match state.world.renderer.as_mut().unwrap().render(&state.window) {
|
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Log the error and exit gracefully
|
// Log the error and exit gracefully
|
||||||
|
|
@ -283,19 +281,9 @@ impl ApplicationHandler<AppState> for App {
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for object in state.clients.iter() {
|
|
||||||
object
|
let elapsed = now.elapsed();
|
||||||
.0
|
//println!("Elapsed {:.2?}",elapsed);
|
||||||
.borrow_mut()
|
|
||||||
.model
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.instance
|
|
||||||
.transform *= Mat4::from_rotation_translation(
|
|
||||||
Quat::from_euler(EulerRot::XYZ, 0.001, -0.001, 0.001),
|
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
WindowEvent::MouseInput {
|
WindowEvent::MouseInput {
|
||||||
button,
|
button,
|
||||||
|
|
|
||||||
|
|
@ -95,17 +95,20 @@ fn sky_aspect(look: vec3<f32>) -> vec4<f32> {
|
||||||
return textureSample(sky_texture, sky_sampler, uv);
|
return textureSample(sky_texture, sky_sampler, uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation(mat: mat4x4<f32>) -> mat3x3<f32> {
|
fn rotation(it: mat4x4<f32>) -> mat3x3<f32> {
|
||||||
return mat3x3<f32>(
|
return mat3x3<f32>(
|
||||||
mat[0].xyz,
|
it[0].xyz,
|
||||||
mat[1].xyz,
|
it[1].xyz,
|
||||||
mat[2].xyz,
|
it[2].xyz,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translation(mat: mat4x4<f32>) -> vec4<f32> {
|
fn translation(it: mat4x4<f32>) -> vec4<f32> {
|
||||||
//return vec4<f32>(mat[0][3],mat[1][3],mat[2][3],mat[3][3]);
|
return it[3];
|
||||||
return mat[3];
|
}
|
||||||
|
|
||||||
|
fn light_aspect(light: vec3<f32>, dir: vec3<f32>) -> vec4<f32> {
|
||||||
|
return vec4<f32>(0.0,0.0,0.0,0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
|
|
@ -131,7 +134,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
//let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0);
|
//let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0);
|
||||||
//let specular_color = specular_strength * environment.light.xyz;
|
//let specular_color = specular_strength * environment.light.xyz;
|
||||||
|
|
||||||
let reflect_factor = max(object_rough.x * 0.5,object_rough.y);
|
let reflect_factor = pow(object_rough.x,3);
|
||||||
|
|
||||||
let diffuse_brightness = length(diffuse_color);
|
let diffuse_brightness = length(diffuse_color);
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -3,3 +3,5 @@ pub mod app;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod web;
|
pub mod web;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
pub mod list;
|
||||||
|
pub mod state;
|
||||||
185
src/list.rs
Normal file
185
src/list.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
type Index = u32;
|
||||||
|
|
||||||
|
pub struct Element<T> {
|
||||||
|
it: Option<T>,
|
||||||
|
count: Index,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FreeList<T> {
|
||||||
|
items: Vec<Option<T>>,
|
||||||
|
free: Vec<Index>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq,Hash,PartialEq)]
|
||||||
|
pub struct SingleId<T> {
|
||||||
|
index: Index,
|
||||||
|
phantom_data: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<SingleId<T>> for Id<T> {
|
||||||
|
fn from(value: SingleId<T>) -> Self {
|
||||||
|
Id {
|
||||||
|
index: value.index,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SingleId<T> {
|
||||||
|
pub(crate) fn shared(self) -> Id<T> {
|
||||||
|
Id {
|
||||||
|
index: self.index,
|
||||||
|
phantom_data: self.phantom_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Id<T> {
|
||||||
|
index: Index,
|
||||||
|
phantom_data: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefId<'a, T> {
|
||||||
|
pub id: Id<T>,
|
||||||
|
it: &'a mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Deref for RefId<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> DerefMut for RefId<'a, T> {
|
||||||
|
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<RefId<'_, T>> for Id<T> {
|
||||||
|
fn from(value: RefId<T>) -> Self {
|
||||||
|
value.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for Id<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Id {
|
||||||
|
index: self.index,
|
||||||
|
phantom_data: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PartialEq for Id<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.index == other.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Eq for Id<T> {}
|
||||||
|
|
||||||
|
impl<T> Hash for Id<T> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.index.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Id<T> {
|
||||||
|
pub fn maybe(self) -> MaybeId<T> {
|
||||||
|
MaybeId(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MaybeId<T>(Id<T>);
|
||||||
|
|
||||||
|
impl<T> From<Id<T>> for MaybeId<T> {
|
||||||
|
fn from(value: Id<T>) -> Self {
|
||||||
|
MaybeId(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for MaybeId<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
if self.0.index != u32::MAX {
|
||||||
|
MaybeId(self.0.clone())
|
||||||
|
} else {
|
||||||
|
MaybeId::NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MaybeId<T> {
|
||||||
|
pub const NULL: MaybeId<T> = MaybeId(Id { index: u32::MAX, phantom_data: PhantomData {}, });
|
||||||
|
pub fn unwrap(self) -> Id<T> {
|
||||||
|
if self.0.index == u32::MAX {
|
||||||
|
panic!()
|
||||||
|
} else {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn exists(&self) -> Option<Id<T>> {
|
||||||
|
if self.0.index == u32::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for FreeList<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FreeList<T> {
|
||||||
|
pub fn new() -> FreeList<T> {
|
||||||
|
FreeList {
|
||||||
|
items: Vec::new(),
|
||||||
|
free: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get(&mut self, id: &Id<T>) -> &mut T {
|
||||||
|
self.items[id.index as usize].as_mut().unwrap()
|
||||||
|
}
|
||||||
|
pub fn get_ref(&mut self, id: Id<T>) -> RefId<'_, T> {
|
||||||
|
let it = self.get(&id);
|
||||||
|
RefId { id, it }
|
||||||
|
}
|
||||||
|
pub fn remove(&mut self, id: Id<T>) -> T {
|
||||||
|
self.free.push(id.index);
|
||||||
|
self.items[id.index as usize].take().unwrap()
|
||||||
|
}
|
||||||
|
pub fn make(&mut self, value: T) -> RefId<'_, T> { // todo: shouldn't panic if allocation fails
|
||||||
|
if let Some(free) = self.free.pop() {
|
||||||
|
self.items[free as usize] = Some(value);
|
||||||
|
RefId {
|
||||||
|
id: Id {
|
||||||
|
index: free,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
},
|
||||||
|
it: self.items[free as usize].as_mut().unwrap(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.items.push(Some(value));
|
||||||
|
let index = (self.items.len() - 1) as Index;
|
||||||
|
RefId {
|
||||||
|
id: Id {
|
||||||
|
index,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
},
|
||||||
|
it: self.items[index as usize].as_mut().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::render::{MaterialProperties, SimpleTexture};
|
use crate::render::{MaterialProperties, Texture};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use glam::camera::lh::proj::directx::perspective;
|
use glam::camera::lh::proj::directx::perspective;
|
||||||
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
|
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
|
||||||
|
|
@ -49,7 +49,7 @@ impl Eye {
|
||||||
bytemuck::cast_slice(&[self.environment]),
|
bytemuck::cast_slice(&[self.environment]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
pub(crate) fn new(device: &Device, width: u32, height: u32, skybox: SimpleTexture) -> Eye {
|
pub(crate) fn new(device: &Device, width: u32, height: u32, skybox: Texture) -> Eye {
|
||||||
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Camera Buffer"),
|
label: Some("Camera Buffer"),
|
||||||
contents: bytemuck::cast_slice(&[
|
contents: bytemuck::cast_slice(&[
|
||||||
|
|
@ -136,7 +136,7 @@ impl Eye {
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
camera: &wgpu::Buffer,
|
camera: &wgpu::Buffer,
|
||||||
environment: &wgpu::Buffer,
|
environment: &wgpu::Buffer,
|
||||||
skybox: SimpleTexture,
|
skybox: Texture,
|
||||||
) -> wgpu::BindGroup {
|
) -> wgpu::BindGroup {
|
||||||
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: &layout,
|
layout: &layout,
|
||||||
|
|
@ -163,7 +163,7 @@ impl Eye {
|
||||||
label: Some("eye_bind_group"),
|
label: Some("eye_bind_group"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn skybox(&mut self, device: &wgpu::Device, texture: SimpleTexture) {
|
pub fn skybox(&mut self, device: &wgpu::Device, texture: Texture) {
|
||||||
self.group = Eye::bind_group(
|
self.group = Eye::bind_group(
|
||||||
&self.layout,
|
&self.layout,
|
||||||
device,
|
device,
|
||||||
|
|
@ -172,8 +172,9 @@ impl Eye {
|
||||||
texture,
|
texture,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub(crate) fn resize(&mut self, width: u32, height: u32) {
|
pub(crate) fn resize(&mut self, queue: &Queue, width: u32, height: u32) {
|
||||||
self.aspect_ratio = width as f32 / height as f32
|
self.aspect_ratio = width as f32 / height as f32;
|
||||||
|
self.write(queue);
|
||||||
}
|
}
|
||||||
pub(crate) fn control(&mut self, delta: Vec3) {
|
pub(crate) fn control(&mut self, delta: Vec3) {
|
||||||
self.frame *= Affine3A::from_translation(delta);
|
self.frame *= Affine3A::from_translation(delta);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
pub mod eye;
|
pub mod eye;
|
||||||
|
|
||||||
use crate::render::eye::Eye;
|
use crate::render::eye::Eye;
|
||||||
use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData};
|
use crate::world::{Shape, ColliderData, ObjectData, World, AABB};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use glam::prelude::*;
|
use glam::prelude::*;
|
||||||
use gltf::Semantic;
|
use gltf::Semantic;
|
||||||
|
|
@ -18,12 +18,18 @@ use wgpu::naga::{FastHashMap, FastHashSet};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use wgpu::{Device, Queue};
|
use wgpu::{Device, Queue};
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
use crate::list::{FreeList, SingleId, Id, RefId};
|
||||||
|
use crate::world;
|
||||||
|
|
||||||
const DEFAULT_VERTICES: [SimpleVertex; 0] = [];
|
const DEFAULT_VERTICES: [TangentVertex; 0] = [];
|
||||||
|
|
||||||
|
pub struct Screen {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||||
pub struct SimpleModelInstance {
|
pub struct ModelInstance {
|
||||||
pub transform: Mat4,
|
pub transform: Mat4,
|
||||||
pub color: Vec4,
|
pub color: Vec4,
|
||||||
pub lights: [u16; 16],
|
pub lights: [u16; 16],
|
||||||
|
|
@ -35,64 +41,61 @@ pub struct SimpleModelInstance {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Pod, Copy, Clone, Zeroable)]
|
#[derive(Pod, Copy, Clone, Zeroable)]
|
||||||
pub struct SimpleLightInstance {
|
pub struct LightInstance {
|
||||||
pub location: Vec4,
|
pub location: Vec4,
|
||||||
pub rotation: Vec4,
|
pub rotation: Vec4,
|
||||||
pub color: Vec4,
|
pub color: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleLightData {
|
pub struct LightData {
|
||||||
pub index: usize,
|
pub instance: LightInstance,
|
||||||
pub instance: SimpleLightInstance,
|
|
||||||
pub transform: Affine3,
|
pub transform: Affine3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleModelData {
|
pub struct ModelData {
|
||||||
pub instance: SimpleModelInstance,
|
pub instance: ModelInstance,
|
||||||
pub material: Id<SimpleMaterial>,
|
pub material: Id<Material>,
|
||||||
pub mesh: Id<SimpleMesh>,
|
pub mesh: Id<Mesh>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SimpleInstances {
|
pub struct Instances {
|
||||||
light_count: usize,
|
light_count: usize,
|
||||||
light_buffer: wgpu::Buffer,
|
light_buffer: wgpu::Buffer,
|
||||||
instance_count: usize,
|
instance_count: usize,
|
||||||
instance_buffer: wgpu::Buffer,
|
instance_buffer: wgpu::Buffer,
|
||||||
//light_ref_last: usize,
|
models_flag: bool,
|
||||||
//light_ref_buffer: wgpu::Buffer,
|
program: Program,
|
||||||
objects:
|
models: FastHashMap<Id<Mesh>, FastHashMap<Id<Material>, FastHashMap<Id<ObjectData>,bool>>>,
|
||||||
FastHashMap<Id<SimpleMesh>, FastHashMap<Id<SimpleMaterial>, FastHashSet<SimpleObject>>>,
|
|
||||||
lights: FastHashMap<SimpleLight, usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SimpleRenderCode {
|
enum Code {
|
||||||
Material(wgpu::BindGroup),
|
Material(Material),
|
||||||
Mesh((wgpu::Buffer, u32), Option<(wgpu::Buffer, u32)>),
|
Mesh(Mesh),
|
||||||
Draw(Range<u32>),
|
Draw(Range<u32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimpleRenderProgram(Vec<SimpleRenderCode>);
|
struct Program(Vec<Code>);
|
||||||
|
|
||||||
impl SimpleRenderProgram {
|
impl Program {
|
||||||
fn push(&mut self, item: SimpleRenderCode) {
|
fn push(&mut self, item: Code) {
|
||||||
self.0.push(item)
|
self.0.push(item)
|
||||||
}
|
}
|
||||||
fn new() -> SimpleRenderProgram {
|
fn new() -> Program {
|
||||||
SimpleRenderProgram(Vec::new())
|
Program(Vec::new())
|
||||||
}
|
}
|
||||||
fn render(self, pass: &mut wgpu::RenderPass) {
|
fn render(self, pass: &mut wgpu::RenderPass) {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut indexed = false;
|
let mut indexed = false;
|
||||||
for code in self.0 {
|
for code in self.0 {
|
||||||
match code {
|
match code {
|
||||||
SimpleRenderCode::Material(material) => pass.set_bind_group(
|
Code::Material(material) => pass.set_bind_group(
|
||||||
Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,
|
Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,
|
||||||
&material,
|
&material.group,
|
||||||
&[],
|
&[],
|
||||||
),
|
),
|
||||||
SimpleRenderCode::Mesh(vertices, indices) => {
|
Code::Mesh(Mesh {vertices, indices, ..}) => {
|
||||||
pass.set_vertex_buffer(0, vertices.0.slice(..));
|
pass.set_vertex_buffer(0, vertices.0.slice(..));
|
||||||
if let Some(indices) = indices {
|
if let Some(indices) = indices {
|
||||||
pass.set_index_buffer(indices.0.slice(..), wgpu::IndexFormat::Uint32);
|
pass.set_index_buffer(indices.0.slice(..), wgpu::IndexFormat::Uint32);
|
||||||
|
|
@ -103,7 +106,7 @@ impl SimpleRenderProgram {
|
||||||
indexed = false;
|
indexed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SimpleRenderCode::Draw(instances) => {
|
Code::Draw(instances) => {
|
||||||
if indexed {
|
if indexed {
|
||||||
pass.draw_indexed(0..count, 0, instances)
|
pass.draw_indexed(0..count, 0, instances)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -115,42 +118,20 @@ impl SimpleRenderProgram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleInstances {
|
impl Instances {
|
||||||
const MIN_SIZE: u64 = 64;
|
const MIN_SIZE: u64 = 64;
|
||||||
pub fn add_object(&mut self, object: SimpleObject) {
|
pub fn register_object(&mut self, mut object: RefId<ObjectData>) {
|
||||||
if let Some(ref model) = object.0.borrow().model {
|
let model = object.model.as_mut().unwrap();
|
||||||
self.instance_count += 1;
|
self.instance_count += 1;
|
||||||
self.objects
|
self.models
|
||||||
.entry(model.mesh.clone())
|
.entry(model.mesh.clone()).or_default()
|
||||||
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
|
.entry(model.material.clone()).or_default()
|
||||||
.entry(model.material.clone())
|
.insert(object.into(),self.models_flag);
|
||||||
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
|
|
||||||
.insert(object.clone());
|
|
||||||
}
|
}
|
||||||
}
|
/*pub fn register_light(&mut self, light: Id<LightData>) {
|
||||||
|
|
||||||
pub fn remove_object(&mut self, object: SimpleObject) {
|
|
||||||
if let Some(ref model) = object.0.borrow().model {
|
|
||||||
self.instance_count -= 1;
|
|
||||||
self.objects
|
|
||||||
.entry(model.mesh.clone())
|
|
||||||
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
|
|
||||||
.entry(model.material.clone())
|
|
||||||
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
|
|
||||||
.remove(&object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_light(&mut self, light: SimpleLight) {
|
|
||||||
self.light_count += 1;
|
self.light_count += 1;
|
||||||
self.lights.insert(light, 0);
|
self.lights.insert(light);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
pub fn remove_light(&mut self, light: &SimpleLight) {
|
|
||||||
self.light_count -= 1;
|
|
||||||
self.lights.remove(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reallocate_buffer(
|
pub fn reallocate_buffer(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
buffer: &mut wgpu::Buffer,
|
buffer: &mut wgpu::Buffer,
|
||||||
|
|
@ -158,7 +139,7 @@ impl SimpleInstances {
|
||||||
item_size: usize,
|
item_size: usize,
|
||||||
) {
|
) {
|
||||||
let size = buffer.size() / item_size as wgpu::BufferAddress;
|
let size = buffer.size() / item_size as wgpu::BufferAddress;
|
||||||
if count > SimpleInstances::MIN_SIZE as usize {
|
if count > Instances::MIN_SIZE as usize {
|
||||||
let mut reallocate: Option<usize> = None;
|
let mut reallocate: Option<usize> = None;
|
||||||
if count < (size / 2) as usize {
|
if count < (size / 2) as usize {
|
||||||
reallocate = Some(count / 2);
|
reallocate = Some(count / 2);
|
||||||
|
|
@ -175,7 +156,7 @@ impl SimpleInstances {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn write_lights(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) {
|
/*pub fn write_lights(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) {
|
||||||
//SimpleInstances::reallocate_buffer(device, queue, &mut self.light_ref_buffer, self.light_ref_last, size_of::<u32>());
|
//SimpleInstances::reallocate_buffer(device, queue, &mut self.light_ref_buffer, self.light_ref_last, size_of::<u32>());
|
||||||
/*
|
/*
|
||||||
let mut light_ref_buffer = queue.write_buffer_with(
|
let mut light_ref_buffer = queue.write_buffer_with(
|
||||||
|
|
@ -184,11 +165,11 @@ impl SimpleInstances {
|
||||||
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
|
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
*/
|
*/
|
||||||
SimpleInstances::reallocate_buffer(
|
Instances::reallocate_buffer(
|
||||||
device,
|
device,
|
||||||
&mut self.light_buffer,
|
&mut self.light_buffer,
|
||||||
self.light_count,
|
self.light_count,
|
||||||
size_of::<SimpleLight>(),
|
size_of::<WorldLight>(),
|
||||||
);
|
);
|
||||||
let mut buffer = queue
|
let mut buffer = queue
|
||||||
.write_buffer_with(
|
.write_buffer_with(
|
||||||
|
|
@ -197,7 +178,7 @@ impl SimpleInstances {
|
||||||
wgpu::BufferSize::new(self.light_buffer.size()).unwrap(),
|
wgpu::BufferSize::new(self.light_buffer.size()).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let stride = size_of::<SimpleLight>();
|
let stride = size_of::<WorldLight>();
|
||||||
for (new_index, (light, index)) in self.lights.iter_mut().enumerate() {
|
for (new_index, (light, index)) in self.lights.iter_mut().enumerate() {
|
||||||
*index = new_index + 1;
|
*index = new_index + 1;
|
||||||
let begin = *index * stride;
|
let begin = *index * stride;
|
||||||
|
|
@ -205,18 +186,20 @@ impl SimpleInstances {
|
||||||
.slice(begin..begin + stride)
|
.slice(begin..begin + stride)
|
||||||
.copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
|
.copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
fn write_instances(
|
fn write_instances(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
mesh_list: &mut FreeList<Mesh>,
|
||||||
|
material_list: &mut FreeList<Material>,
|
||||||
|
objects_list: &mut FreeList<ObjectData>,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
) -> SimpleRenderProgram {
|
) {
|
||||||
let mut program = SimpleRenderProgram::new();
|
Instances::reallocate_buffer(
|
||||||
SimpleInstances::reallocate_buffer(
|
|
||||||
device,
|
device,
|
||||||
&mut self.instance_buffer,
|
&mut self.instance_buffer,
|
||||||
self.instance_count,
|
self.instance_count,
|
||||||
size_of::<SimpleModelInstance>(),
|
size_of::<ModelInstance>(),
|
||||||
);
|
);
|
||||||
let mut buffer = queue
|
let mut buffer = queue
|
||||||
.write_buffer_with(
|
.write_buffer_with(
|
||||||
|
|
@ -226,37 +209,33 @@ impl SimpleInstances {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut index: u32 = 0;
|
let mut index: u32 = 0;
|
||||||
let stride = size_of::<SimpleModelInstance>();
|
let stride = size_of::<ModelInstance>();
|
||||||
for (mesh, materials) in self.objects.iter() {
|
for (mesh, materials) in self.models.iter_mut() {
|
||||||
program.push(SimpleRenderCode::Mesh(
|
self.program.push(Code::Mesh(mesh_list.get(mesh).clone()));
|
||||||
mesh.it.vertices.clone(),
|
for (material, objects) in materials.iter_mut() {
|
||||||
mesh.it.indices.clone(),
|
self.program.push(Code::Material(material_list.get(material).clone()));
|
||||||
));
|
|
||||||
for (material, objects) in materials.iter() {
|
|
||||||
program.push(SimpleRenderCode::Material(material.it.group.clone()));
|
|
||||||
let before = index;
|
let before = index;
|
||||||
for object in objects.iter() {
|
objects.retain(|object,flag| {
|
||||||
|
let object = objects_list.get(object);
|
||||||
|
if *flag == self.models_flag {
|
||||||
let begin = index as usize * stride;
|
let begin = index as usize * stride;
|
||||||
buffer
|
buffer.slice(begin..begin + stride).copy_from_slice(bytemuck::cast_slice(&[object.model.as_mut().unwrap().instance]));
|
||||||
.slice(begin..begin + stride)
|
|
||||||
.copy_from_slice(bytemuck::cast_slice(&[object
|
|
||||||
.0
|
|
||||||
.borrow()
|
|
||||||
.model
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.instance]));
|
|
||||||
index += 1;
|
index += 1;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
program.push(SimpleRenderCode::Draw(Range::from(before..index)));
|
});
|
||||||
|
self.program.push(Code::Draw(before..index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
program
|
//println!("objects: {}",index);
|
||||||
|
self.models_flag = !self.models_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desc() -> wgpu::VertexBufferLayout<'static> {
|
fn desc() -> wgpu::VertexBufferLayout<'static> {
|
||||||
wgpu::VertexBufferLayout {
|
wgpu::VertexBufferLayout {
|
||||||
array_stride: size_of::<SimpleModelInstance>() as wgpu::BufferAddress,
|
array_stride: size_of::<ModelInstance>() as wgpu::BufferAddress,
|
||||||
step_mode: wgpu::VertexStepMode::Instance,
|
step_mode: wgpu::VertexStepMode::Instance,
|
||||||
attributes: &[
|
attributes: &[
|
||||||
// todo: is this too big?
|
// todo: is this too big?
|
||||||
|
|
@ -304,17 +283,17 @@ impl SimpleInstances {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(device: &wgpu::Device) -> SimpleInstances {
|
pub fn new(device: &wgpu::Device) -> Instances {
|
||||||
let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("Instance Buffer"),
|
label: Some("Instance Buffer"),
|
||||||
size: (size_of::<SimpleModelInstance>() * SimpleInstances::MIN_SIZE as usize)
|
size: (size_of::<ModelInstance>() * Instances::MIN_SIZE as usize)
|
||||||
as wgpu::BufferAddress,
|
as wgpu::BufferAddress,
|
||||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
let light_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let light_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("Light Buffer"),
|
label: Some("Light Buffer"),
|
||||||
size: (size_of::<SimpleLightInstance>() * SimpleInstances::MIN_SIZE as usize)
|
size: (size_of::<LightInstance>() * Instances::MIN_SIZE as usize)
|
||||||
as wgpu::BufferAddress,
|
as wgpu::BufferAddress,
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
|
|
@ -325,38 +304,44 @@ impl SimpleInstances {
|
||||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});*/
|
});*/
|
||||||
SimpleInstances {
|
Instances {
|
||||||
light_count: 0,
|
light_count: 0,
|
||||||
//light_ref_last: 0,
|
//light_ref_last: 0,
|
||||||
instance_count: 0,
|
instance_count: 0,
|
||||||
light_buffer,
|
light_buffer,
|
||||||
instance_buffer,
|
instance_buffer,
|
||||||
//light_ref_buffer,
|
//light_ref_buffer,
|
||||||
objects: FastHashMap::with_hasher(BuildHasherDefault::new()),
|
//lights: Default::default(),
|
||||||
lights: Default::default(),
|
models_flag: false,
|
||||||
|
program: Program(Vec::new()),
|
||||||
|
models: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
id_count: u64,
|
|
||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
config: wgpu::SurfaceConfiguration,
|
config: wgpu::SurfaceConfiguration,
|
||||||
device: wgpu::Device,
|
device: wgpu::Device,
|
||||||
queue: wgpu::Queue,
|
queue: wgpu::Queue,
|
||||||
|
materials: FreeList<Material>,
|
||||||
|
textures: FreeList<Texture>,
|
||||||
|
meshes: FreeList<Mesh>,
|
||||||
|
light_instances: FreeList<LightData>,
|
||||||
|
model_instances: FreeList<ModelData>,
|
||||||
pub(crate) eye: eye::Eye,
|
pub(crate) eye: eye::Eye,
|
||||||
material_layout: wgpu::BindGroupLayout,
|
material_layout: wgpu::BindGroupLayout,
|
||||||
default_texture: SimpleTexture,
|
default_texture: Texture,
|
||||||
default_material: SimpleMaterial,
|
default_material: Material,
|
||||||
sky_pipeline: wgpu::RenderPipeline,
|
sky_pipeline: wgpu::RenderPipeline,
|
||||||
instance_pipeline: wgpu::RenderPipeline,
|
instance_pipeline: wgpu::RenderPipeline,
|
||||||
depth_texture: SimpleTexture,
|
depth_texture: Texture,
|
||||||
pub(crate) instances: SimpleInstances,
|
pub(crate) instances: Instances,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
struct SimpleVertex {
|
struct TangentVertex {
|
||||||
position: [f32; 3],
|
position: [f32; 3],
|
||||||
normal: [f32; 3],
|
normal: [f32; 3],
|
||||||
tex_coord: [f32; 2],
|
tex_coord: [f32; 2],
|
||||||
|
|
@ -364,10 +349,18 @@ struct SimpleVertex {
|
||||||
bitangent: [f32; 3],
|
bitangent: [f32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleVertex {
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
struct Vertex {
|
||||||
|
position: [f32; 3],
|
||||||
|
normal: [f32; 3],
|
||||||
|
tex_coord: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TangentVertex {
|
||||||
fn desc() -> wgpu::VertexBufferLayout<'static> {
|
fn desc() -> wgpu::VertexBufferLayout<'static> {
|
||||||
wgpu::VertexBufferLayout {
|
wgpu::VertexBufferLayout {
|
||||||
array_stride: size_of::<SimpleVertex>() as wgpu::BufferAddress,
|
array_stride: size_of::<TangentVertex>() as wgpu::BufferAddress,
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
attributes: &[
|
attributes: &[
|
||||||
wgpu::VertexAttribute {
|
wgpu::VertexAttribute {
|
||||||
|
|
@ -390,12 +383,13 @@ impl SimpleVertex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SimpleMesh {
|
pub struct Mesh {
|
||||||
indices: Option<(wgpu::Buffer, u32)>,
|
indices: Option<(wgpu::Buffer, u32)>,
|
||||||
vertices: (wgpu::Buffer, u32),
|
vertices: (wgpu::Buffer, u32),
|
||||||
|
aabb: AABB,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct SimpleTexture {
|
pub struct Texture {
|
||||||
texture: wgpu::Texture,
|
texture: wgpu::Texture,
|
||||||
view: wgpu::TextureView,
|
view: wgpu::TextureView,
|
||||||
}
|
}
|
||||||
|
|
@ -404,13 +398,38 @@ pub struct TextureProperties {
|
||||||
height: u32,
|
height: u32,
|
||||||
}
|
}
|
||||||
// todo: use texture compression!
|
// todo: use texture compression!
|
||||||
impl SimpleTexture {
|
impl Texture {
|
||||||
|
pub fn depth(config: &wgpu::SurfaceConfiguration, device: &Device) -> Texture {
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
// 2.
|
||||||
|
width: config.width.max(1),
|
||||||
|
height: config.height.max(1),
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
let desc = wgpu::TextureDescriptor {
|
||||||
|
label: Some("depth texture"),
|
||||||
|
size,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3.
|
||||||
|
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||||
|
view_formats: &[],
|
||||||
|
};
|
||||||
|
let _depth_texture = device.create_texture(&desc);
|
||||||
|
let depth_view = _depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
Texture {
|
||||||
|
texture: _depth_texture,
|
||||||
|
view: depth_view,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn load(
|
pub fn load(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
slice: impl AsRef<[u8]>,
|
slice: impl AsRef<[u8]>,
|
||||||
properties: TextureProperties,
|
properties: TextureProperties,
|
||||||
) -> SimpleTexture {
|
) -> Texture {
|
||||||
let size = wgpu::Extent3d {
|
let size = wgpu::Extent3d {
|
||||||
width: properties.width,
|
width: properties.width,
|
||||||
height: properties.height,
|
height: properties.height,
|
||||||
|
|
@ -443,7 +462,7 @@ impl SimpleTexture {
|
||||||
},
|
},
|
||||||
size,
|
size,
|
||||||
);
|
);
|
||||||
SimpleTexture {
|
Texture {
|
||||||
texture: diffuse_texture,
|
texture: diffuse_texture,
|
||||||
view: diffuse_texture_view,
|
view: diffuse_texture_view,
|
||||||
}
|
}
|
||||||
|
|
@ -451,30 +470,10 @@ impl SimpleTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleMaterial {
|
pub struct Material {
|
||||||
group: wgpu::BindGroup,
|
group: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Id<T> {
|
|
||||||
id: u64,
|
|
||||||
it: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Hash for Id<T> {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.id.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PartialEq for Id<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
other.id == self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Eq for Id<T> {}
|
|
||||||
|
|
||||||
struct MaterialProperties {
|
struct MaterialProperties {
|
||||||
edge: wgpu::AddressMode,
|
edge: wgpu::AddressMode,
|
||||||
filter: wgpu::FilterMode,
|
filter: wgpu::FilterMode,
|
||||||
|
|
@ -503,15 +502,15 @@ impl MaterialProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleMaterial {
|
impl Material {
|
||||||
fn new(
|
fn new(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
layout: &wgpu::BindGroupLayout,
|
layout: &wgpu::BindGroupLayout,
|
||||||
base: &SimpleTexture,
|
base: &Texture,
|
||||||
normal: &SimpleTexture,
|
normal: &Texture,
|
||||||
reflect: &SimpleTexture,
|
reflect: &Texture,
|
||||||
config: MaterialProperties,
|
config: MaterialProperties,
|
||||||
) -> SimpleMaterial {
|
) -> Material {
|
||||||
let sampler = config.sampler(&device);
|
let sampler = config.sampler(&device);
|
||||||
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: layout,
|
layout: layout,
|
||||||
|
|
@ -535,7 +534,7 @@ impl SimpleMaterial {
|
||||||
],
|
],
|
||||||
label: Some("diffuse_bind_group"),
|
label: Some("diffuse_bind_group"),
|
||||||
});
|
});
|
||||||
SimpleMaterial { group }
|
Material { group }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,14 +549,14 @@ impl Display for PoolError {
|
||||||
|
|
||||||
impl Error for PoolError {}
|
impl Error for PoolError {}
|
||||||
|
|
||||||
pub struct SimpleTreeNode {
|
pub struct TreeNode {
|
||||||
object: Option<SimpleObject>,
|
object: Option<ObjectData>,
|
||||||
children: Vec<SimpleTreeNode>,
|
children: Vec<TreeNode>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleTreeNode {
|
impl TreeNode {
|
||||||
pub fn first_object(&self) -> Option<SimpleObject> {
|
pub fn first_object(&self) -> Option<ObjectData> {
|
||||||
if let Some(object) = self.object.clone() {
|
if let Some(object) = self.object.clone() {
|
||||||
Some(object)
|
Some(object)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -577,18 +576,14 @@ impl Renderer {
|
||||||
const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0;
|
const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0;
|
||||||
const SIMPLE_RENDER_TEXTURE_GROUP_POSITION: u32 = 1;
|
const SIMPLE_RENDER_TEXTURE_GROUP_POSITION: u32 = 1;
|
||||||
const SIMPLE_RENDER_MODEL_GROUP_POSITION: u32 = 2;
|
const SIMPLE_RENDER_MODEL_GROUP_POSITION: u32 = 2;
|
||||||
pub fn new_id<T>(&mut self, value: T) -> Id<T> {
|
pub fn write_instances(&mut self, objects: &mut FreeList<ObjectData>) {
|
||||||
self.id_count += 1;
|
self.instances.write_instances(&mut self.meshes, &mut self.materials, objects, &self.device, &self.queue);
|
||||||
Id {
|
|
||||||
it: value,
|
|
||||||
id: self.id_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn load_texture_from_bytes(
|
pub fn load_texture_from_bytes(
|
||||||
&mut self,
|
&mut self,
|
||||||
slice: impl AsRef<[u8]>,
|
slice: impl AsRef<[u8]>,
|
||||||
format: Option<image::ImageFormat>,
|
format: Option<image::ImageFormat>,
|
||||||
) -> SimpleTexture {
|
) -> Texture {
|
||||||
let image = if let Some(format) = format {
|
let image = if let Some(format) = format {
|
||||||
image::load_from_memory_with_format(slice.as_ref(), format)
|
image::load_from_memory_with_format(slice.as_ref(), format)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -596,7 +591,7 @@ impl Renderer {
|
||||||
};
|
};
|
||||||
if let Ok(data) = image {
|
if let Ok(data) = image {
|
||||||
let data = data.into_rgba8();
|
let data = data.into_rgba8();
|
||||||
SimpleTexture::load(
|
Texture::load(
|
||||||
&self.device,
|
&self.device,
|
||||||
&self.queue,
|
&self.queue,
|
||||||
data.as_bytes(),
|
data.as_bytes(),
|
||||||
|
|
@ -612,11 +607,11 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
pub fn new_material(
|
pub fn new_material(
|
||||||
&mut self,
|
&mut self,
|
||||||
base: &SimpleTexture,
|
base: &Texture,
|
||||||
normal: &SimpleTexture,
|
normal: &Texture,
|
||||||
reflect: &SimpleTexture,
|
reflect: &Texture,
|
||||||
) -> Id<SimpleMaterial> {
|
) -> Id<Material> {
|
||||||
self.new_id(SimpleMaterial::new(
|
self.materials.make(Material::new(
|
||||||
&self.device,
|
&self.device,
|
||||||
&self.material_layout,
|
&self.material_layout,
|
||||||
base,
|
base,
|
||||||
|
|
@ -626,13 +621,13 @@ impl Renderer {
|
||||||
edge: wgpu::AddressMode::Repeat,
|
edge: wgpu::AddressMode::Repeat,
|
||||||
filter: wgpu::FilterMode::Linear,
|
filter: wgpu::FilterMode::Linear,
|
||||||
},
|
},
|
||||||
))
|
)).into()
|
||||||
}
|
}
|
||||||
pub fn new_texture_from_gltf(
|
pub fn new_texture_from_gltf(
|
||||||
&mut self,
|
&mut self,
|
||||||
info: &gltf::texture::Texture,
|
info: &gltf::texture::Texture,
|
||||||
images: &Vec<gltf::image::Data>,
|
images: &Vec<gltf::image::Data>,
|
||||||
) -> SimpleTexture {
|
) -> Texture {
|
||||||
if let Some(image) = images.get(info.source().index()) {
|
if let Some(image) = images.get(info.source().index()) {
|
||||||
let mut new_pixels = Vec::new();
|
let mut new_pixels = Vec::new();
|
||||||
let pixels: &Vec<u8>;
|
let pixels: &Vec<u8>;
|
||||||
|
|
@ -649,7 +644,7 @@ impl Renderer {
|
||||||
gltf::image::Format::R8G8B8A8 => pixels = &image.pixels,
|
gltf::image::Format::R8G8B8A8 => pixels = &image.pixels,
|
||||||
_ => return self.default_texture.clone(),
|
_ => return self.default_texture.clone(),
|
||||||
}
|
}
|
||||||
SimpleTexture::load(
|
Texture::load(
|
||||||
&self.device,
|
&self.device,
|
||||||
&self.queue,
|
&self.queue,
|
||||||
pixels.as_slice(),
|
pixels.as_slice(),
|
||||||
|
|
@ -665,42 +660,38 @@ impl Renderer {
|
||||||
pub fn new_mesh_from_gltf(
|
pub fn new_mesh_from_gltf(
|
||||||
&mut self,
|
&mut self,
|
||||||
primitive: gltf::Primitive,
|
primitive: gltf::Primitive,
|
||||||
meshes: &mut HashMap<GltfVertexBufferKey, SimpleMesh>,
|
meshes: &mut HashMap<GltfVertexBufferKey, Mesh>,
|
||||||
buffers: &[gltf::buffer::Data],
|
buffers: &[gltf::buffer::Data],
|
||||||
) -> Id<SimpleMesh> {
|
) -> RefId<Mesh> {
|
||||||
let position_index = primitive
|
let position_index = primitive
|
||||||
.get(&Semantic::Positions)
|
.get(&Semantic::Positions)
|
||||||
.and_then(|it| it.view())
|
.and_then(|it| it.view()).map(|it| it.buffer().index());
|
||||||
.and_then(|it| Some(it.buffer().index()));
|
|
||||||
let normals_index = primitive
|
let normals_index = primitive
|
||||||
.get(&Semantic::Normals)
|
.get(&Semantic::Normals)
|
||||||
.and_then(|it| it.view())
|
.and_then(|it| it.view()).map(|it| it.buffer().index());
|
||||||
.and_then(|it| Some(it.buffer().index()));
|
|
||||||
let tex_coords_index = primitive
|
let tex_coords_index = primitive
|
||||||
.get(&Semantic::TexCoords(0))
|
.get(&Semantic::TexCoords(0))
|
||||||
.and_then(|it| it.view())
|
.and_then(|it| it.view()).map(|it| it.buffer().index());
|
||||||
.and_then(|it| Some(it.buffer().index()));
|
|
||||||
let indices_index = primitive
|
let indices_index = primitive
|
||||||
.indices()
|
.indices()
|
||||||
.and_then(|it| it.view())
|
.and_then(|it| it.view()).map(|it| it.buffer().index());
|
||||||
.and_then(|it| Some(it.buffer().index()));
|
|
||||||
let tangent_index = primitive
|
let tangent_index = primitive
|
||||||
.get(&Semantic::Tangents)
|
.get(&Semantic::Tangents)
|
||||||
.and_then(|it| it.view())
|
.and_then(|it| it.view()).map(|it| it.buffer().index());
|
||||||
.and_then(|it| Some(it.buffer().index()));
|
|
||||||
let key = (
|
let key = (
|
||||||
position_index,
|
position_index,
|
||||||
normals_index,
|
normals_index,
|
||||||
tex_coords_index,
|
tex_coords_index,
|
||||||
indices_index,
|
indices_index,
|
||||||
);
|
);
|
||||||
self.new_id(
|
self.meshes.make(
|
||||||
meshes
|
meshes
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
let mut tangents = false;
|
let mut tangents = false;
|
||||||
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
|
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
|
||||||
let mut vertex_data: Vec<SimpleVertex>;
|
let mut vertex_data: Vec<TangentVertex>;
|
||||||
|
let mut aabb = AABB(Vec3::ZERO,Vec3::ZERO);
|
||||||
if let Some(positions) = reader.read_positions() {
|
if let Some(positions) = reader.read_positions() {
|
||||||
vertex_data = Vec::with_capacity(positions.len());
|
vertex_data = Vec::with_capacity(positions.len());
|
||||||
let mut normal = reader.read_normals().map(|it| it.into_iter());
|
let mut normal = reader.read_normals().map(|it| it.into_iter());
|
||||||
|
|
@ -710,7 +701,8 @@ impl Renderer {
|
||||||
let mut tangent = reader.read_tangents().map(|it| it.into_iter());
|
let mut tangent = reader.read_tangents().map(|it| it.into_iter());
|
||||||
tangents = tangent.is_some();
|
tangents = tangent.is_some();
|
||||||
for position in positions {
|
for position in positions {
|
||||||
vertex_data.push(SimpleVertex {
|
aabb = aabb.extend_to(Vec3::from(position));
|
||||||
|
vertex_data.push(TangentVertex {
|
||||||
position,
|
position,
|
||||||
normal: if let Some(ref mut normals) = normal {
|
normal: if let Some(ref mut normals) = normal {
|
||||||
if let Some(normal) = normals.next() {
|
if let Some(normal) = normals.next() {
|
||||||
|
|
@ -756,9 +748,10 @@ impl Renderer {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
SimpleMesh {
|
Mesh {
|
||||||
indices: indices_result,
|
indices: indices_result,
|
||||||
vertices: vertices_result,
|
vertices: vertices_result,
|
||||||
|
aabb,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
@ -767,12 +760,12 @@ impl Renderer {
|
||||||
pub fn load_node_from_gltf(
|
pub fn load_node_from_gltf(
|
||||||
&mut self,
|
&mut self,
|
||||||
node: gltf::Node,
|
node: gltf::Node,
|
||||||
meshes: &mut HashMap<GltfVertexBufferKey, SimpleMesh>,
|
meshes: &mut HashMap<GltfVertexBufferKey, Mesh>,
|
||||||
textures: &mut HashMap<usize, SimpleTexture>,
|
textures: &mut HashMap<usize, Texture>,
|
||||||
images: &Vec<gltf::image::Data>,
|
images: &Vec<gltf::image::Data>,
|
||||||
buffers: &Vec<gltf::buffer::Data>,
|
buffers: &Vec<gltf::buffer::Data>,
|
||||||
) -> SimpleTreeNode {
|
) -> TreeNode {
|
||||||
let mut tree_node = SimpleTreeNode {
|
let mut tree_node = TreeNode {
|
||||||
object: None,
|
object: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
name: node.name().unwrap_or("Node").to_string(),
|
name: node.name().unwrap_or("Node").to_string(),
|
||||||
|
|
@ -809,9 +802,10 @@ impl Renderer {
|
||||||
};
|
};
|
||||||
let material = self.new_material(&base, &normal, &reflect);
|
let material = self.new_material(&base, &normal, &reflect);
|
||||||
let mesh = self.new_mesh_from_gltf(primitive, meshes, buffers);
|
let mesh = self.new_mesh_from_gltf(primitive, meshes, buffers);
|
||||||
let object = SimpleObject(Rc::new(RefCell::new(SimpleObjectData {
|
let aabb = mesh.aabb;
|
||||||
model: Some(SimpleModelData {
|
let object = ObjectData {
|
||||||
instance: SimpleModelInstance {
|
model: Some(ModelData {
|
||||||
|
instance: ModelInstance {
|
||||||
transform: Mat4::default(),
|
transform: Mat4::default(),
|
||||||
color: Vec4::from_array(color),
|
color: Vec4::from_array(color),
|
||||||
lights: [0; 16],
|
lights: [0; 16],
|
||||||
|
|
@ -821,17 +815,16 @@ impl Renderer {
|
||||||
rough,
|
rough,
|
||||||
},
|
},
|
||||||
material,
|
material,
|
||||||
mesh,
|
mesh: mesh.into(),
|
||||||
}),
|
}),
|
||||||
collider: SimpleColliderData {
|
collider: ColliderData { shape: Shape::Sphere(aabb.1.distance(aabb.0)) },
|
||||||
transform: Mat4::default(),
|
affine: Default::default(),
|
||||||
shape: Shape::None,
|
asleep: false,
|
||||||
},
|
};
|
||||||
})));
|
|
||||||
if len == 1 {
|
if len == 1 {
|
||||||
tree_node.object = Some(object);
|
tree_node.object = Some(object);
|
||||||
} else {
|
} else {
|
||||||
tree_node.children.push(SimpleTreeNode {
|
tree_node.children.push(TreeNode {
|
||||||
object: Some(object),
|
object: Some(object),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
name: "Primitive".to_string(),
|
name: "Primitive".to_string(),
|
||||||
|
|
@ -846,17 +839,17 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
tree_node
|
tree_node
|
||||||
}
|
}
|
||||||
pub fn load_from_gltf(&mut self, slice: impl AsRef<[u8]>) -> SimpleTreeNode {
|
pub fn load_from_gltf(&mut self, slice: impl AsRef<[u8]>) -> TreeNode {
|
||||||
let mut root = SimpleTreeNode {
|
let mut root = TreeNode {
|
||||||
object: None,
|
object: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
name: "Root".to_string(),
|
name: "Root".to_string(),
|
||||||
};
|
};
|
||||||
if let Ok((document, buffers, images)) = gltf::import_slice(slice) {
|
if let Ok((document, buffers, images)) = gltf::import_slice(slice) {
|
||||||
let mut meshes: HashMap<GltfVertexBufferKey, SimpleMesh> = HashMap::new();
|
let mut meshes: HashMap<GltfVertexBufferKey, Mesh> = HashMap::new();
|
||||||
let mut textures: HashMap<usize, SimpleTexture> = HashMap::new();
|
let mut textures: HashMap<usize, Texture> = HashMap::new();
|
||||||
for scene in document.scenes() {
|
for scene in document.scenes() {
|
||||||
let mut scene_node = SimpleTreeNode {
|
let mut scene_node = TreeNode {
|
||||||
object: None,
|
object: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
name: scene.name().unwrap_or("Scene").to_string(),
|
name: scene.name().unwrap_or("Scene").to_string(),
|
||||||
|
|
@ -876,12 +869,14 @@ impl Renderer {
|
||||||
root
|
root
|
||||||
}
|
}
|
||||||
pub fn resize(&mut self, width: u32, height: u32) {
|
pub fn resize(&mut self, width: u32, height: u32) {
|
||||||
|
println!("resize");
|
||||||
|
self.config.width = width;
|
||||||
|
self.config.height = height;
|
||||||
|
self.depth_texture = Texture::depth(&self.config,&self.device);
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
self.eye.resize(width, height);
|
self.eye.resize(&self.queue, width, height);
|
||||||
}
|
}
|
||||||
|
pub fn set_skybox(&mut self, skybox: Texture) {
|
||||||
|
|
||||||
pub fn set_skybox(&mut self, skybox: SimpleTexture) {
|
|
||||||
self.eye.skybox(&self.device, skybox);
|
self.eye.skybox(&self.device, skybox);
|
||||||
}
|
}
|
||||||
pub async fn new(window: &Arc<Window>) -> anyhow::Result<Self> {
|
pub async fn new(window: &Arc<Window>) -> anyhow::Result<Self> {
|
||||||
|
|
@ -917,6 +912,7 @@ impl Renderer {
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
force_fallback_adapter: false,
|
force_fallback_adapter: false,
|
||||||
|
//apply_limit_buckets: false,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
@ -950,9 +946,10 @@ impl Renderer {
|
||||||
let config = wgpu::SurfaceConfiguration {
|
let config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format: surface_format,
|
format: surface_format,
|
||||||
|
//color_space: Default::default(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
present_mode: surface_caps.present_modes[0],
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
alpha_mode: surface_caps.alpha_modes[0],
|
alpha_mode: surface_caps.alpha_modes[0],
|
||||||
view_formats: vec![],
|
view_formats: vec![],
|
||||||
desired_maximum_frame_latency: 2,
|
desired_maximum_frame_latency: 2,
|
||||||
|
|
@ -961,7 +958,7 @@ impl Renderer {
|
||||||
let shader =
|
let shader =
|
||||||
device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl"));
|
device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl"));
|
||||||
|
|
||||||
let default_texture = SimpleTexture::load(
|
let default_texture = Texture::load(
|
||||||
&device,
|
&device,
|
||||||
&queue,
|
&queue,
|
||||||
[0, 0, 255, 255],
|
[0, 0, 255, 255],
|
||||||
|
|
@ -1027,7 +1024,7 @@ impl Renderer {
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: Some("vs_main"),
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[SimpleVertex::desc(), SimpleInstances::desc()],
|
buffers: &[TangentVertex::desc(), Instances::desc()],
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
|
@ -1104,48 +1101,11 @@ impl Renderer {
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let size = wgpu::Extent3d {
|
let instances = Instances::new(&device);
|
||||||
// 2.
|
|
||||||
width: config.width.max(1),
|
|
||||||
height: config.height.max(1),
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
};
|
|
||||||
let desc = wgpu::TextureDescriptor {
|
|
||||||
label: Some("depth texture"),
|
|
||||||
size,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Depth32Float,
|
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3.
|
|
||||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
|
||||||
view_formats: &[],
|
|
||||||
};
|
|
||||||
let depth_texture = device.create_texture(&desc);
|
|
||||||
let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
|
||||||
// 4.
|
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
||||||
mag_filter: wgpu::FilterMode::Linear,
|
|
||||||
min_filter: wgpu::FilterMode::Linear,
|
|
||||||
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
|
|
||||||
compare: Some(wgpu::CompareFunction::LessEqual), // 5.
|
|
||||||
lod_min_clamp: 0.0,
|
|
||||||
lod_max_clamp: 100.0,
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
let instances = SimpleInstances::new(&device);
|
let depth_texture = Texture::depth(&config,&device);
|
||||||
|
|
||||||
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let default_material = Material::new(
|
||||||
label: Some("Vertex Buffer"),
|
|
||||||
contents: bytemuck::cast_slice(&DEFAULT_VERTICES),
|
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
|
||||||
});
|
|
||||||
|
|
||||||
let default_material = SimpleMaterial::new(
|
|
||||||
&device,
|
&device,
|
||||||
&texture_bind_group_layout,
|
&texture_bind_group_layout,
|
||||||
&default_texture,
|
&default_texture,
|
||||||
|
|
@ -1155,14 +1115,10 @@ impl Renderer {
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Renderer {
|
Ok(Renderer {
|
||||||
id_count: 0,
|
|
||||||
material_layout: texture_bind_group_layout,
|
material_layout: texture_bind_group_layout,
|
||||||
default_texture,
|
default_texture,
|
||||||
default_material,
|
default_material,
|
||||||
depth_texture: SimpleTexture {
|
depth_texture,
|
||||||
texture: depth_texture,
|
|
||||||
view: depth_view,
|
|
||||||
},
|
|
||||||
instances,
|
instances,
|
||||||
sky_pipeline,
|
sky_pipeline,
|
||||||
instance_pipeline,
|
instance_pipeline,
|
||||||
|
|
@ -1170,28 +1126,31 @@ impl Renderer {
|
||||||
config,
|
config,
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
|
materials: Default::default(),
|
||||||
|
textures: Default::default(),
|
||||||
|
meshes: Default::default(),
|
||||||
|
light_instances: Default::default(),
|
||||||
|
model_instances: Default::default(),
|
||||||
eye,
|
eye,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub(crate) fn render(&mut self, window: &Arc<Window>) -> anyhow::Result<()> {
|
pub(crate) fn render(&mut self, window: &Arc<Window>, objects: &mut FreeList<ObjectData>) -> anyhow::Result<()> {
|
||||||
window.request_redraw();
|
let surface_texture = match self.surface.get_current_texture() {
|
||||||
|
|
||||||
let mut resize_renderer = false;
|
|
||||||
|
|
||||||
let output = match self.surface.get_current_texture() {
|
|
||||||
wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
|
wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
|
||||||
wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => {
|
wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => {
|
||||||
resize_renderer = true; //moved reconfigure to avoid a crash when resizing window
|
println!("suboptimal");
|
||||||
surface_texture
|
self.surface.configure(&self.device, &self.config);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
wgpu::CurrentSurfaceTexture::Timeout
|
wgpu::CurrentSurfaceTexture::Timeout
|
||||||
| wgpu::CurrentSurfaceTexture::Occluded
|
| wgpu::CurrentSurfaceTexture::Occluded
|
||||||
| wgpu::CurrentSurfaceTexture::Validation => {
|
| wgpu::CurrentSurfaceTexture::Validation => {
|
||||||
// Skip this frame
|
println!("timeout");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
wgpu::CurrentSurfaceTexture::Outdated => {
|
wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
|
println!("outdated");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
wgpu::CurrentSurfaceTexture::Lost => {
|
wgpu::CurrentSurfaceTexture::Lost => {
|
||||||
|
|
@ -1200,18 +1159,20 @@ impl Renderer {
|
||||||
anyhow::bail!("Lost device");
|
anyhow::bail!("Lost device");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let view = output
|
|
||||||
|
let view = surface_texture
|
||||||
.texture
|
.texture
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
let program = self.instances.write_instances(&self.device, &self.queue);
|
|
||||||
|
|
||||||
let mut encoder = self
|
let mut encoder = self
|
||||||
.device
|
.device
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
label: Some("Render Encoder"),
|
label: Some("Render Encoder"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.eye.write(&self.queue);
|
||||||
|
self.instances.write_instances(&mut self.meshes, &mut self.materials, objects, &self.device, &self.queue);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
|
|
@ -1245,7 +1206,7 @@ impl Renderer {
|
||||||
pass.set_pipeline(&self.instance_pipeline);
|
pass.set_pipeline(&self.instance_pipeline);
|
||||||
pass.set_bind_group(0, &self.eye.group, &[]);
|
pass.set_bind_group(0, &self.eye.group, &[]);
|
||||||
pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..));
|
pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..));
|
||||||
program.render(&mut pass);
|
std::mem::replace(&mut self.instances.program,Program(Vec::new())).render(&mut pass); // todo: improve
|
||||||
|
|
||||||
pass.set_bind_group(1, &self.default_material.group, &[]);
|
pass.set_bind_group(1, &self.default_material.group, &[]);
|
||||||
|
|
||||||
|
|
@ -1255,24 +1216,24 @@ impl Renderer {
|
||||||
|
|
||||||
self.queue.submit(Some(encoder.finish()));
|
self.queue.submit(Some(encoder.finish()));
|
||||||
|
|
||||||
self.eye.write(&self.queue);
|
window.pre_present_notify();
|
||||||
|
|
||||||
output.present();
|
surface_texture.present();
|
||||||
|
//self.queue.present(surface_texture);
|
||||||
|
|
||||||
|
// its rust just being stupid
|
||||||
if(resize_renderer){
|
//std::mem::drop(view); // idk how this would affect a multi-pass system like deferred rendering, but this makes sure it's not gonna collide with resizing the swap chain or whatever wGPU does
|
||||||
std::mem::drop(view); //idk how this would affect a multi-pass system like deferred rendering, but this makes sure it's not gonna collide with resizing the swap chain or whatever wGPU does
|
|
||||||
self.surface.configure(&self.device, &self.config);
|
|
||||||
/*
|
/*
|
||||||
also in this snippet call the functions to
|
also in this snippet call the functions to
|
||||||
a: resize window resolution
|
a: resize window resolution // todo: idk why it's ignoring me
|
||||||
b: resize projection
|
b: resize projection // done: made eye.rs write to eye buffer
|
||||||
currently when you resize the window the projection matrix is not updated
|
currently when you resize the window the projection matrix is not updated
|
||||||
and therefore it gets very skewed and weird looking if you resize the current
|
and therefore it gets very skewed and weird looking if you resize the current
|
||||||
small window to a big screen like mine(halbear) which is 3440x1440
|
small window to a big screen like mine(halbear) which is 3440x1440
|
||||||
i would add it myself but i don't know wGPU or rust all that well sooooo
|
i would add it myself but i don't know wGPU or rust all that well sooooo
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
window.request_redraw();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/state.rs
Normal file
19
src/state.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
use crate::list::FreeList;
|
||||||
|
use crate::{render, world};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct State {
|
||||||
|
pub objects: FreeList<world::ObjectData>,
|
||||||
|
pub lights: FreeList<render::LightData>,
|
||||||
|
pub worlds: FreeList<world::World>,
|
||||||
|
pub renderer: Option<render::Renderer>,
|
||||||
|
pub screens: FreeList<render::Screen>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new() -> State {
|
||||||
|
State {
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/ui/mod.rs
Normal file
0
src/ui/mod.rs
Normal file
589
src/world/mod.rs
589
src/world/mod.rs
|
|
@ -1,116 +1,304 @@
|
||||||
use crate::render::{Renderer, SimpleLightData, SimpleModelData};
|
use glam::{Affine3, IVec3, Mat4, Quat, Vec3};
|
||||||
use glam::{IVec3, Mat4, Vec3};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
||||||
|
use std::path::absolute;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use mars::vm::Object;
|
||||||
use wgpu::naga::{FastHashMap, FastHashSet};
|
use wgpu::naga::{FastHashMap, FastHashSet};
|
||||||
|
use crate::{list, render};
|
||||||
|
use crate::list::{FreeList, Id, MaybeId, RefId, SingleId};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
Block(Vec3),
|
Block(Vec3),
|
||||||
Sphere(f32),
|
Sphere(f32),
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleColliderData {
|
pub struct ColliderData {
|
||||||
pub transform: Mat4,
|
|
||||||
pub shape: Shape,
|
pub shape: Shape,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleColliderData {
|
impl ColliderData {
|
||||||
fn aabb(&self) -> Option<AABB> {
|
fn aabb(&self, affine: Affine3) -> AABB {
|
||||||
let (_scale, _rotation, translation) = self.transform.to_scale_rotation_translation();
|
let (_scale, _rotation, translation) = affine.to_scale_rotation_translation();
|
||||||
match self.shape {
|
match self.shape {
|
||||||
Shape::Block(size) => {
|
Shape::Block(size) => {
|
||||||
let radius_offset = Vec3::splat(size.length());
|
let radius_offset = Vec3::splat(size.length());
|
||||||
Some(AABB(
|
AABB(
|
||||||
translation - radius_offset,
|
translation - radius_offset,
|
||||||
translation + radius_offset,
|
translation + radius_offset,
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
Shape::Sphere(radius) => {
|
Shape::Sphere(radius) => {
|
||||||
let radius_offset = Vec3::splat(radius);
|
let radius_offset = Vec3::splat(radius);
|
||||||
Some(AABB(
|
AABB(
|
||||||
translation - radius_offset,
|
translation - radius_offset,
|
||||||
translation + radius_offset,
|
translation + radius_offset,
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
Shape::None => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleObjectData {
|
pub struct ObjectData {
|
||||||
pub model: Option<SimpleModelData>,
|
pub model: Option<render::ModelData>,
|
||||||
pub collider: SimpleColliderData,
|
pub collider: ColliderData,
|
||||||
|
pub affine: Affine3,
|
||||||
|
pub asleep: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
pub enum InterestType {
|
||||||
|
Light(Id<render::LightData>),
|
||||||
|
Object(Id<ObjectData>)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleLight(pub Rc<RefCell<SimpleLightData>>);
|
pub struct Interest {
|
||||||
|
it: InterestType,
|
||||||
impl PartialEq for SimpleLight {
|
aabb: AABB,
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
Rc::ptr_eq(&self.0, &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for SimpleLight {}
|
|
||||||
|
|
||||||
impl Hash for SimpleLight {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
(self.0.as_ptr() as *const RefCell<SimpleLight>).hash(state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleObject(pub Rc<RefCell<SimpleObjectData>>);
|
pub struct InterestNode {
|
||||||
|
interest: Interest,
|
||||||
|
next: MaybeId<InterestNode>,
|
||||||
|
}
|
||||||
|
|
||||||
impl SimpleObject {
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(crate) fn hard_clone(&self) -> SimpleObject {
|
pub struct AABB(pub(crate) Vec3, pub(crate) Vec3);
|
||||||
SimpleObject {
|
|
||||||
0: Rc::new(RefCell::new(SimpleObjectData {
|
impl AABB {
|
||||||
model: self.0.borrow().model.clone(),
|
pub(crate) fn new(translation: Vec3, size: Vec3) -> AABB {
|
||||||
collider: self.0.borrow().collider.clone(),
|
AABB(translation - size, translation + size)
|
||||||
})),
|
}
|
||||||
|
pub fn extend_to(&self, point: Vec3) -> AABB {
|
||||||
|
AABB(self.0.min(point),self.1.max(point))
|
||||||
|
}
|
||||||
|
pub fn bounded_by(&self, aabb: AABB) -> AABB {
|
||||||
|
AABB(self.0.max(aabb.0), self.1.min(aabb.1))
|
||||||
|
}
|
||||||
|
fn offset(&self) -> Vec3 {
|
||||||
|
self.1 - self.0
|
||||||
|
}
|
||||||
|
fn to_iaabb(&self) -> IAABB {
|
||||||
|
IAABB(self.0.as_ivec3(),self.1.as_ivec3())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct IAABB(pub(crate) IVec3, pub(crate) IVec3);
|
||||||
|
|
||||||
|
impl IAABB {
|
||||||
|
pub(crate) fn new(translation: IVec3, size: IVec3) -> IAABB {
|
||||||
|
IAABB(translation - size, translation + size)
|
||||||
|
}
|
||||||
|
pub fn extend_to(&self, point: IVec3) -> IAABB {
|
||||||
|
IAABB(self.0.min(point),self.1.max(point))
|
||||||
|
}
|
||||||
|
pub fn bounded_by(&self, aabb: IAABB) -> IAABB {
|
||||||
|
IAABB(self.0.max(aabb.0), self.1.min(aabb.1))
|
||||||
|
}
|
||||||
|
fn offset(&self) -> IVec3 {
|
||||||
|
self.1 - self.0
|
||||||
|
}
|
||||||
|
fn to_aabb(self) -> AABB {
|
||||||
|
AABB(self.0.as_vec3(),self.1.as_vec3())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct World {
|
||||||
|
pub(crate) matter: OctreeMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for World {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OctreeDebug {
|
||||||
|
map: FastHashMap<IVec3, Id<ObjectData>>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum OctreeDebugOperation {
|
||||||
|
Add(IVec3,i32),
|
||||||
|
Remove(IVec3),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OctreeDebug {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OctreeDebug {
|
||||||
|
pub fn new() -> OctreeDebug {
|
||||||
|
OctreeDebug {
|
||||||
|
map: FastHashMap::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_block(
|
||||||
|
&mut self,
|
||||||
|
blocks: &mut FreeList<OctreeBlock>,
|
||||||
|
block: Id<OctreeBlock>,
|
||||||
|
objects: &mut FreeList<ObjectData>,
|
||||||
|
debug: &Option<render::ModelData>,
|
||||||
|
pos: IVec3,
|
||||||
|
size: i32
|
||||||
|
) {
|
||||||
|
let entry = self.map.get(&pos);
|
||||||
|
if let Some(debug) = debug {
|
||||||
|
if entry.is_none() {
|
||||||
|
let mut model = debug.clone();
|
||||||
|
model.instance.transform = Mat4::from_scale_rotation_translation(Vec3::splat(size as f32),Quat::IDENTITY,pos.as_vec3());
|
||||||
|
self.map.insert(pos, objects.make(ObjectData {
|
||||||
|
model: Some(model),
|
||||||
|
collider: ColliderData {
|
||||||
|
shape: Shape::Sphere(size as f32),
|
||||||
|
},
|
||||||
|
affine: Default::default(),
|
||||||
|
asleep: false,
|
||||||
|
}).id);
|
||||||
|
println!("pos {} size {}",pos,size)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if entry.is_some() {
|
||||||
|
objects.remove(self.map.remove(&pos).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[0].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug, pos - (IVec3::new(-1, -1, -1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[1].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,-1,-1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[2].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,1,-1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[3].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,1,-1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[4].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,-1,1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[5].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,-1,1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[6].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,1,1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
if let Some(block) = blocks.get(&block).blocks[7].exists() {
|
||||||
|
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,1,1) * size / 4), size / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set(&mut self, objects: &mut FreeList<ObjectData>, world: &mut World, debug: Option<render::ModelData>) {
|
||||||
|
for (index,block) in world.matter.map.iter_mut() {
|
||||||
|
self.set_block(
|
||||||
|
&mut world.matter.blocks,
|
||||||
|
block.clone(),
|
||||||
|
objects,
|
||||||
|
&debug,
|
||||||
|
index * OctreeBlock::CHUNK_SIZE,
|
||||||
|
OctreeBlock::CHUNK_SIZE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn register(&mut self, objects: &mut FreeList<ObjectData>, renderer: &mut render::Renderer) {
|
||||||
|
for (pos,block) in self.map.iter() {
|
||||||
|
renderer.instances.register_object(objects.get_ref(block.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for SimpleObject {
|
impl World {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
pub fn new() -> World {
|
||||||
Rc::ptr_eq(&self.0, &other.0)
|
World {
|
||||||
}
|
matter: OctreeMap::new(),
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for SimpleObject {}
|
}
|
||||||
|
}
|
||||||
|
pub fn add_object(&mut self, object: RefId<ObjectData>) -> Id<ObjectData> {
|
||||||
|
self.matter.place_interest(Interest {
|
||||||
|
it: InterestType::Object(object.id.clone()),
|
||||||
|
aabb: object.collider.aabb(object.affine),
|
||||||
|
});
|
||||||
|
object.id
|
||||||
|
}
|
||||||
|
pub fn remove_object(&mut self, object: Id<ObjectData>) {
|
||||||
|
|
||||||
impl Hash for SimpleObject {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
(self.0.as_ptr() as *const RefCell<SimpleModelData>).hash(state);
|
|
||||||
}
|
}
|
||||||
}
|
pub fn step(
|
||||||
|
&mut self,
|
||||||
#[derive(Eq, Hash, PartialEq, Clone)]
|
maybe_renderer: &mut Option<render::Renderer>,
|
||||||
pub enum Interest {
|
objects: &mut FreeList<ObjectData>,
|
||||||
Light(SimpleLight),
|
_lights: &mut FreeList<render::LightData>,
|
||||||
Object(SimpleObject),
|
) {
|
||||||
}
|
/*fn reinsert(
|
||||||
|
block_id: &Id<OctreeBlock>,
|
||||||
impl Interest {
|
blocks: &mut FreeList<OctreeBlock>,
|
||||||
fn aabb(&self) -> Option<AABB> {
|
interests: &mut FreeList<InterestNode>,
|
||||||
match self {
|
objects: &mut FreeList<ObjectData>
|
||||||
Interest::Light(light) => {
|
) {
|
||||||
let data = light.0.borrow();
|
let mut maybe_interest = &blocks.get(block_id).first;
|
||||||
Some(AABB::new(
|
while let Some(interest_id) = maybe_interest.exists() {
|
||||||
data.transform.to_scale_rotation_translation().2,
|
let interest = interests.get(&interest_id);
|
||||||
Vec3::splat(data.instance.color.length()),
|
match interest.interest.it {
|
||||||
))
|
InterestType::Object(ref object_id) => {
|
||||||
|
let mut object = objects.get_ref(object_id.clone());
|
||||||
|
let transform = Mat4::from_mat3_translation(object.affine.matrix3, object.affine.translation);
|
||||||
|
object.model.as_mut().unwrap().instance.transform = transform;
|
||||||
|
instances.register_object(object)
|
||||||
}
|
}
|
||||||
Interest::Object(object) => object.0.borrow().collider.aabb(),
|
_ => {}
|
||||||
|
}
|
||||||
|
maybe_interest = &interest.next;
|
||||||
|
}
|
||||||
|
for id in blocks.get(block_id).blocks.clone().iter() {
|
||||||
|
if let Some(id) = id.exists() {
|
||||||
|
reinsert(&id, blocks, interests, objects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for (_pos,id) in self.matter.map.iter() {
|
||||||
|
reinsert(id, &mut self.matter.blocks, &mut self.matter.interests, objects)
|
||||||
|
}*/
|
||||||
|
if let Some(renderer) = maybe_renderer {
|
||||||
|
fn consider(
|
||||||
|
block_id: &Id<OctreeBlock>,
|
||||||
|
renderer: &mut render::Renderer,
|
||||||
|
blocks: &mut FreeList<OctreeBlock>,
|
||||||
|
interests: &mut FreeList<InterestNode>,
|
||||||
|
objects: &mut FreeList<ObjectData>
|
||||||
|
) {
|
||||||
|
let mut maybe_interest = &blocks.get(block_id).first;
|
||||||
|
while let Some(interest_id) = maybe_interest.exists() {
|
||||||
|
let interest = interests.get(&interest_id);
|
||||||
|
match interest.interest.it {
|
||||||
|
InterestType::Object(ref object_id) => {
|
||||||
|
let mut object = objects.get_ref(object_id.clone());
|
||||||
|
let transform = Mat4::from_mat3_translation(object.affine.matrix3,object.affine.translation);
|
||||||
|
object.model.as_mut().unwrap().instance.transform = transform;
|
||||||
|
renderer.instances.register_object(object)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
maybe_interest = &interest.next;
|
||||||
|
}
|
||||||
|
for id in blocks.get(block_id).blocks.clone().iter() {
|
||||||
|
if let Some(id) = id.exists() {
|
||||||
|
consider(&id, renderer, blocks, interests, objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (_pos,id) in self.matter.map.iter() {
|
||||||
|
consider(id, renderer, &mut self.matter.blocks, &mut self.matter.interests, objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn sync(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
@ -125,188 +313,153 @@ impl Material {
|
||||||
Material {
|
Material {
|
||||||
volume: 0,
|
volume: 0,
|
||||||
velocity: Vec3::ZERO,
|
velocity: Vec3::ZERO,
|
||||||
material: 0,
|
material: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
impl OctreeBlock {
|
||||||
struct AABB(Vec3, Vec3);
|
|
||||||
|
|
||||||
impl AABB {
|
|
||||||
fn new(translation: Vec3, size: Vec3) -> AABB {
|
|
||||||
AABB(translation - size, translation + size)
|
|
||||||
}
|
|
||||||
fn bounded_by(&self, aabb: AABB) -> AABB {
|
|
||||||
AABB(self.0.max(aabb.0), self.1.min(aabb.1))
|
|
||||||
}
|
|
||||||
fn offset(&self) -> Vec3 {
|
|
||||||
self.1 - self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct World {
|
|
||||||
map: HashedMap,
|
|
||||||
pub renderer: Option<Renderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl World {
|
|
||||||
pub fn new() -> World {
|
|
||||||
World {
|
|
||||||
map: HashedMap::new(),
|
|
||||||
renderer: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn renderer(&mut self) -> &mut Renderer {
|
|
||||||
self.renderer.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
pub fn add_renderer(&mut self, renderer: Renderer) {
|
|
||||||
self.renderer = Some(renderer);
|
|
||||||
}
|
|
||||||
pub fn add_object(&mut self, object: SimpleObject) {
|
|
||||||
if let Some(aabb) = object.0.borrow().collider.aabb() {
|
|
||||||
self.map
|
|
||||||
.place_with_aabb(Interest::Object(object.clone()), aabb);
|
|
||||||
}
|
|
||||||
if let Some(ref mut renderer) = self.renderer
|
|
||||||
&& object.0.borrow().model.is_some()
|
|
||||||
{
|
|
||||||
renderer.instances.add_object(object.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn remove_object(&mut self, object: SimpleObject) {}
|
|
||||||
pub fn set_debug(&mut self, value: Option<SimpleObject>) {
|
|
||||||
for (index, item) in self.map.it.iter_mut() {}
|
|
||||||
}
|
|
||||||
fn step(&mut self) {}
|
|
||||||
fn sync(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
type VecMap<T> = FastHashMap<IVec3,T>;
|
|
||||||
|
|
||||||
struct Level<T,S> {
|
|
||||||
sub_level:
|
|
||||||
entries: T
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MatterLevel<T> {
|
|
||||||
blocks: Option<VecMap<Material>>
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InterestLevel<T> {
|
|
||||||
blocks: Option<VecMap<Interest>>
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HashedMap {
|
|
||||||
matter:
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HashedMap {
|
|
||||||
fn new() -> HashedMap {
|
|
||||||
HashedMap {
|
|
||||||
it: FastHashMap::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*impl Block {
|
|
||||||
const FLOOR: i32 = 4;
|
const FLOOR: i32 = 4;
|
||||||
const CHUNK_SIZE: i32 = Block::FLOOR * 64;
|
const CHUNK_SIZE: i32 = OctreeBlock::FLOOR * 64;
|
||||||
const MAX_IDEAL_INTEREST: usize = 4;
|
const MAX_IDEAL_INTEREST: usize = 4;
|
||||||
fn new() -> Block {
|
fn new() -> OctreeBlock {
|
||||||
Block {
|
OctreeBlock {
|
||||||
debug: None,
|
interests: 0,
|
||||||
material: Material::new(),
|
material: Material::new(),
|
||||||
interests: FastHashSet::default(),
|
first: MaybeId::NULL,
|
||||||
blocks: None,
|
blocks: [MaybeId::NULL;8],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Blocks = Box<[Block; 8]>;
|
struct OctreeBlock {
|
||||||
|
interests: u32, // 1
|
||||||
struct Block {
|
first: MaybeId<InterestNode>, // 1
|
||||||
debug: Option<SimpleObject>,
|
material: Material, // 4
|
||||||
interests: FastHashSet<Interest>,
|
blocks: Blocks, // 8
|
||||||
material: Material,
|
|
||||||
blocks: Option<Blocks>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl OctreeBlock {
|
||||||
pub fn set_debug(&mut self, value: Option<SimpleObject>, pos: Vec3, size: f32) {}
|
fn push(&mut self, interests: &mut FreeList<InterestNode>, interest: Interest) {
|
||||||
|
self.first = interests.make(InterestNode {
|
||||||
|
interest: interest.clone(),
|
||||||
|
next: self.first.clone(),
|
||||||
|
}).id.maybe();
|
||||||
|
self.interests += 1;
|
||||||
|
}
|
||||||
|
fn remove(&mut self, interests: &mut FreeList<InterestNode>, needle: Interest) {
|
||||||
|
let mut maybe_last = MaybeId::NULL;
|
||||||
|
let mut maybe_this = self.first.clone();
|
||||||
|
while let Some(this) = maybe_this.exists() {
|
||||||
|
let interest = interests.get(&this);
|
||||||
|
let next = interest.next.clone();
|
||||||
|
if interest.interest.it == needle.it {
|
||||||
|
self.interests -= 1;
|
||||||
|
if let Some(last) = maybe_last.exists() {
|
||||||
|
interests.get(&last).next = interest.next.clone();
|
||||||
|
} else {
|
||||||
|
self.first = interest.next.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maybe_last = maybe_this;
|
||||||
|
maybe_this = next;
|
||||||
|
}
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
fn place(
|
||||||
|
it: Id<OctreeBlock>,
|
||||||
|
blocks: &mut FreeList<OctreeBlock>,
|
||||||
|
interests: &mut FreeList<InterestNode>,
|
||||||
|
interest: Interest,
|
||||||
|
pos: IVec3,
|
||||||
|
size: i32,
|
||||||
|
) {
|
||||||
|
if pos == IVec3::ZERO || blocks.get(&it).interests < OctreeBlock::MAX_IDEAL_INTEREST as u32 {
|
||||||
|
blocks.get(&it).push(interests,interest)
|
||||||
|
} else {
|
||||||
|
let mut index = 0;
|
||||||
|
let x = if pos.x > 0 {
|
||||||
|
index += 1;
|
||||||
|
-size
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
};
|
||||||
|
let y = if pos.y > 0 {
|
||||||
|
index += 2;
|
||||||
|
-size
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
};
|
||||||
|
let z = if pos.z > 0 {
|
||||||
|
index += 4;
|
||||||
|
-size
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
};
|
||||||
|
let offset = IVec3::new(x,y,z) / 2;
|
||||||
|
println!("pos {} {} {}",pos,pos + offset,size);
|
||||||
|
let id = if let Some(id) = blocks.get(&it).blocks[index as usize].exists() {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
let id = blocks.make(OctreeBlock::new()).id;
|
||||||
|
blocks.get(&it).blocks[index as usize] = id.clone().into();
|
||||||
|
id
|
||||||
|
};
|
||||||
|
OctreeBlock::place(id,blocks,interests,interest,pos + offset,size / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WorldMap {
|
type Blocks = [MaybeId<OctreeBlock>; 8];
|
||||||
fn new() -> Self;
|
|
||||||
fn place_with_aabb(&mut self, interest: Interest, aabb: AABB);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OctreeMap {
|
struct OctreeMap {
|
||||||
it: FastHashMap<IVec3, Block>,
|
interests: FreeList<InterestNode>,
|
||||||
|
blocks: FreeList<OctreeBlock>,
|
||||||
|
map: FastHashMap<IVec3, Id<OctreeBlock>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OctreeMap {
|
impl OctreeMap {
|
||||||
fn place_with_index(&mut self, interest: Interest, mut index: IVec3) {
|
fn place_interest(&mut self, interest: Interest) {
|
||||||
let chunk_index = (index + IVec3::splat(Block::CHUNK_SIZE / 2)) / Block::CHUNK_SIZE;
|
|
||||||
let mut block = self.it.entry(chunk_index).or_insert_with(|| Block::new());
|
|
||||||
let mut offset_size = Block::CHUNK_SIZE / 4;
|
|
||||||
index = index - chunk_index * Block::CHUNK_SIZE;
|
|
||||||
while index != IVec3::ZERO {
|
|
||||||
let blocks = if let Some(ref mut blocks) = block.blocks {
|
|
||||||
blocks
|
|
||||||
} else if block.interests.len() < Block::MAX_IDEAL_INTEREST {
|
|
||||||
block.interests.insert(interest.clone());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
block.blocks = Some(Box::new(core::array::from_fn(|_| Block::new())));
|
|
||||||
block.blocks.as_mut().unwrap()
|
|
||||||
};
|
|
||||||
let mut block_index = 0;
|
|
||||||
if index.x < 0 {
|
|
||||||
index.x += offset_size;
|
|
||||||
} else {
|
|
||||||
index.x -= offset_size;
|
|
||||||
block_index += 1;
|
|
||||||
}
|
|
||||||
if index.y < 0 {
|
|
||||||
index.y += offset_size;
|
|
||||||
} else {
|
|
||||||
index.y -= offset_size;
|
|
||||||
block_index += 2;
|
|
||||||
}
|
|
||||||
if index.z < 0 {
|
|
||||||
index.z += offset_size;
|
|
||||||
} else {
|
|
||||||
index.z -= offset_size;
|
|
||||||
block_index += 4;
|
|
||||||
}
|
|
||||||
block = &mut blocks[block_index];
|
|
||||||
offset_size /= 2;
|
|
||||||
}
|
|
||||||
block.interests.insert(interest.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WorldMap for OctreeMap {
|
|
||||||
fn place_with_aabb(&mut self, interest: Interest, aabb: AABB) {
|
|
||||||
let mut d = 4;
|
let mut d = 4;
|
||||||
let offset = aabb.1 - aabb.0;
|
let offset = interest.aabb.1 - interest.aabb.0;
|
||||||
while offset.element_sum() > (d * 2) as f32 {
|
while offset.element_sum() > (d * 2) as f32 {
|
||||||
d *= 2
|
d *= 2
|
||||||
}
|
}
|
||||||
let iaabb0 = (aabb.0 / d as f32).floor().as_ivec3();
|
let iaabb = IAABB(
|
||||||
let iaabb1 = (aabb.1 / d as f32).ceil().as_ivec3();
|
(interest.aabb.0 / d as f32).floor().as_ivec3() + IVec3::splat(d / 2),
|
||||||
for x in iaabb0.x..iaabb1.x {
|
(interest.aabb.1 / d as f32).floor().as_ivec3() + IVec3::splat(d / 2),
|
||||||
for y in iaabb0.y..iaabb1.y {
|
);
|
||||||
for z in iaabb0.z..iaabb1.z {
|
println!("attempting place I: {} {} {} A: {} {}",iaabb.0,iaabb.1,d,interest.aabb.0,interest.aabb.1);
|
||||||
self.place_with_index(interest.clone(), IVec3::new(x, y, z) * d as i32);
|
for x in iaabb.0.x..iaabb.1.x {
|
||||||
|
for y in iaabb.0.y..iaabb.1.y {
|
||||||
|
for z in iaabb.0.z..iaabb.1.z {
|
||||||
|
let index = IVec3::new(x,y,z);
|
||||||
|
let absolute_pos = index * d;
|
||||||
|
let chunk_index = absolute_pos / OctreeBlock::CHUNK_SIZE;
|
||||||
|
let chunk_pos = chunk_index * OctreeBlock::CHUNK_SIZE;
|
||||||
|
let block = self.map.entry(chunk_index).or_insert_with(|| {
|
||||||
|
self.blocks.make(OctreeBlock::new()).id
|
||||||
|
});
|
||||||
|
let pos = absolute_pos - chunk_pos;
|
||||||
|
println!("placing {} {}",pos,OctreeBlock::CHUNK_SIZE);
|
||||||
|
OctreeBlock::place(
|
||||||
|
block.clone(),
|
||||||
|
&mut self.blocks,
|
||||||
|
&mut self.interests,
|
||||||
|
interest.clone(),
|
||||||
|
pos,
|
||||||
|
OctreeBlock::CHUNK_SIZE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new() -> OctreeMap {
|
fn new() -> OctreeMap {
|
||||||
OctreeMap {
|
OctreeMap {
|
||||||
it: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
interests: Default::default(),
|
||||||
|
blocks: Default::default(),
|
||||||
|
map: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue