Reorganised: renderer;

This commit is contained in:
paladin 2026-09-14 08:15:56 +01:00
parent 905d05bc39
commit afaad0ae0d
16 changed files with 1310 additions and 1170 deletions

View file

@ -1,7 +1,7 @@
use std::collections::HashMap;
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
use crate::render::{ModelData, Renderer};
use crate::world::{World, ObjectData, OctreeDebug};
use crate::render::{loader, Renderer};
use crate::world::{World, ObjectData};
use glam::{Affine3, Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4};
use std::sync::Arc;
#[cfg(target_arch = "wasm32")]
@ -17,7 +17,11 @@ use winit::{
window::Window,
};
use crate::list::Id;
use crate::render::instance::{Material, ModelData};
use crate::render::instance::material::MaterialProperties;
use crate::render::texture::Texture;
use crate::state;
use crate::world::debug::OctreeDebug;
struct Controller {
buttons: HashMap<MouseButton, bool>,
@ -55,36 +59,31 @@ impl AppState {
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_file = loader::load_from_gltf(renderer,include_bytes!("assets/debug.glb"));
let debug_model = debug_file.first_object().unwrap().model.unwrap();
{
let file = renderer.load_from_gltf(include_bytes!("assets/sphere.glb"));
let file = loader::load_from_gltf(renderer,include_bytes!("assets/sphere.glb"));
let mut block = file.first_object().unwrap();
let skybox = renderer.load_texture_from_bytes(
include_bytes!("assets/skybox2.png"),
Some(image::ImageFormat::Png),
);
renderer.set_skybox(skybox);
let color = renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png"), None);
let normal = renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"), None);
let roughness = renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"), None);
let mat = renderer.new_material(&color, &normal, &roughness);
let skybox = Texture::load_from_file_bytes(renderer,include_bytes!("assets/skybox2.png"), None);
renderer.set_skybox(skybox.unwrap());
let color = Texture::load_from_file_bytes(renderer,include_bytes!("assets/plank/color.png"), None);
let normal = Texture::load_from_file_bytes(renderer,include_bytes!("assets/plank/normal.png"), None);
let roughness = Texture::load_from_file_bytes(renderer,include_bytes!("assets/plank/roughness.png"), None);
let mat = Material::new(renderer, &color.unwrap(), &normal.unwrap(), &roughness.unwrap(), MaterialProperties::default());
block.model.as_mut().unwrap().material = mat;
for x in -BLOCKS..=BLOCKS {
for y in -BLOCKS..=BLOCKS {
let id = world.add_object(state.objects.make(block.clone()));
let block = state.objects.get(&id);
{
block.affine = Affine3::from_translation(
Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0),
);
block.model.as_mut().unwrap().instance.color = Vec4::new(
0.3,
(x + BLOCKS) as f32 / BLOCKS as f32,
(y + BLOCKS) as f32 / BLOCKS as f32,
1.0,
);
}
block.set_affine(Affine3::from_translation(
Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0)
));
block.model.as_mut().unwrap().instance.color = Vec4::new(
0.3,
(x + BLOCKS) as f32 / BLOCKS as f32,
(y + BLOCKS) as f32 / BLOCKS as f32,
1.0,
);
}
}
}

View file

@ -1,7 +1,23 @@
#![recursion_limit = "256"]
use std::error::Error;
use std::fmt::{Display, Formatter};
pub mod app;
pub mod render;
pub mod web;
pub mod world;
pub mod list;
pub mod state;
pub mod net;
#[derive(Debug)]
struct PoolError(String);
impl Display for PoolError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for PoolError {}

View file

@ -1,6 +1,6 @@
#![recursion_limit = "256"]
use game::*;
use pool::*;
fn main() {
app::run().unwrap();
}

0
src/net/mod.rs Normal file
View file

View file

@ -1,9 +1,10 @@
use crate::render::{MaterialProperties, Texture};
use crate::render::{Texture};
use bytemuck::{Pod, Zeroable};
use glam::camera::lh::proj::directx::perspective;
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
use wgpu::util::DeviceExt;
use wgpu::{Device, Queue};
use crate::render::instance::material::MaterialProperties;
pub(crate) struct Eye {
pub(crate) frame: Affine3A,
@ -16,6 +17,7 @@ pub(crate) struct Eye {
pub(crate) camera_buffer: wgpu::Buffer,
pub(crate) layout: wgpu::BindGroupLayout,
pub(crate) group: wgpu::BindGroup,
pub sky_pipeline: wgpu::RenderPipeline,
}
#[repr(C)]
@ -49,7 +51,7 @@ impl Eye {
bytemuck::cast_slice(&[self.environment]),
);
}
pub(crate) fn new(device: &Device, width: u32, height: u32, skybox: Texture) -> Eye {
pub(crate) fn new(device: &Device, config: &wgpu::SurfaceConfiguration, width: u32, height: u32, skybox: Texture) -> Eye {
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[
@ -116,6 +118,51 @@ impl Eye {
label: Some("eye_bind_group_layout"),
});
let shader = device.create_shader_module(wgpu::include_wgsl!("sky.wgsl"));
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[Some(&layout)],
immediate_size: 0,
});
//todo: use a pipeline cache!
let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Sky Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_sky"),
compilation_options: Default::default(),
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_sky"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
// 4.
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Cw,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: Some(false),
depth_compare: Some(wgpu::CompareFunction::LessEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let group = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox);
Eye {
@ -129,6 +176,7 @@ impl Eye {
layout,
environment,
environment_buffer,
sky_pipeline,
}
}
fn bind_group(

View file

@ -15,7 +15,6 @@ struct Eye {
frame: mat4x4<f32>,
}
// Vertex shader
@group(0) @binding(0)
var<uniform> eye: Eye;
@group(0) @binding(1)
@ -144,31 +143,3 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(result.xyz,object_color.a);
}
struct SkyOutput {
@builtin(position) position: vec4<f32>,
@location(0) pos: vec4<f32> // unadulterated by WGSL
}
const TRI_VERTICES = array(
vec4(-1.0, -1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
vec4( 1.0, 1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
);
@vertex
fn vs_sky(@builtin(vertex_index) index: u32) -> SkyOutput {
var out: SkyOutput;
out.position = TRI_VERTICES[index];
out.pos = out.position;
return out;
}
@fragment
fn fs_sky(in: SkyOutput) -> @location(0) vec4<f32> {
let look = rotation(eye.frame) * in.pos.xyz;
return sky_aspect(look);
}

View file

@ -0,0 +1,130 @@
use wgpu::Device;
use crate::list::{FreeList, Id};
use crate::render::Renderer;
use crate::render::texture::Texture;
pub struct Materials {
pub(crate) layout: wgpu::BindGroupLayout,
pub(crate) list: FreeList<Material>,
default: Material,
}
impl Materials {
pub(crate) fn new(device: &Device, default: Texture) -> Materials {
fn texture_bind_group_layout_entry(binding: u32) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
}
}
let layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
texture_bind_group_layout_entry(1),
texture_bind_group_layout_entry(2),
texture_bind_group_layout_entry(3),
],
label: Some("texture_bind_group_layout"),
});
let default = Material::_new(
&device,
&layout,
&default,
&default,
&default,
MaterialProperties::default(),
);
Materials {
layout,
list: Default::default(),
default,
}
}
}
#[derive(Clone)]
pub struct Material {
pub(crate) group: wgpu::BindGroup,
}
pub struct MaterialProperties {
pub(crate) edge: wgpu::AddressMode,
pub(crate) filter: wgpu::FilterMode,
}
impl Default for MaterialProperties {
fn default() -> MaterialProperties {
MaterialProperties {
edge: wgpu::AddressMode::Repeat,
filter: wgpu::FilterMode::Linear,
}
}
}
impl MaterialProperties {
pub(crate) fn sampler(&self, device: &wgpu::Device) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: self.edge,
address_mode_v: self.edge,
address_mode_w: self.edge,
mag_filter: self.filter,
min_filter: self.filter,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
})
}
}
impl Material {
pub(crate) fn _new(
device: &wgpu::Device,
layout: &wgpu::BindGroupLayout,
base: &Texture,
normal: &Texture,
reflect: &Texture,
config: MaterialProperties,
) -> Material {
let sampler = config.sampler(&device);
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&base.view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&normal.view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::TextureView(&reflect.view),
},
],
label: Some("diffuse_bind_group"),
});
Material { group }
}
pub fn new(renderer: &mut Renderer, base: &Texture, normal: &Texture, reflect: &Texture, config: MaterialProperties) -> Id<Material> {
renderer.instances.materials.list.make(Material::_new(&renderer.device, &renderer.instances.materials.layout, base, normal, reflect, config)).id
}
}

376
src/render/instance/mod.rs Normal file
View file

@ -0,0 +1,376 @@
pub mod material;
use std::ops::Range;
use bytemuck::{Pod, Zeroable};
use glam::{Affine3, Mat4, Vec4};
use wgpu::{BindGroup, Device};
use wgpu::naga::FastHashMap;
use crate::list::{FreeList, Id, RefId};
use crate::render::{instance, Renderer};
use crate::render::eye::Eye;
pub(crate) use crate::render::instance::material::{Material, Materials};
use crate::render::mesh::{Mesh, TangentVertex};
use crate::render::texture::Texture;
use crate::world::ObjectData;
#[repr(C)]
#[derive(Pod, Zeroable, Copy, Clone)]
pub struct ModelInstance {
pub transform: Mat4,
pub color: Vec4,
pub lights: [u16; 16],
pub point_lights: u32,
pub spot_lights: u32,
pub metal: f32,
pub rough: f32,
}
#[repr(C)]
#[derive(Pod, Copy, Clone, Zeroable)]
pub struct LightInstance {
pub location: Vec4,
pub rotation: Vec4,
pub color: Vec4,
}
#[derive(Clone)]
pub struct LightData {
pub instance: LightInstance,
pub transform: Affine3,
}
#[derive(Clone)]
pub struct ModelData {
pub instance: ModelInstance,
pub material: Id<Material>,
pub mesh: Id<Mesh>,
}
pub struct Instances {
pub materials: Materials,
light_instances: FreeList<LightData>,
model_instances: FreeList<ModelData>,
pub(crate) pipeline: wgpu::RenderPipeline,
light_count: usize,
light_buffer: wgpu::Buffer,
model_count: usize,
pub(crate) model_buffer: wgpu::Buffer,
models_flag: bool,
pub(crate) program: Program,
models: FastHashMap<Id<Mesh>, FastHashMap<Id<Material>, FastHashMap<Id<ObjectData>,bool>>>,
}
pub enum Code {
Material(Material),
Mesh(Mesh),
Draw(Range<u32>),
}
pub struct Program(pub Vec<Code>);
impl Program {
fn push(&mut self, item: Code) {
self.0.push(item)
}
fn new() -> Program {
Program(Vec::new())
}
pub(crate) fn render(self, pass: &mut wgpu::RenderPass) {
let mut count = 0;
let mut indexed = false;
for code in self.0 {
match code {
Code::Material(material) => pass.set_bind_group(
Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,
&material.group,
&[],
),
Code::Mesh(Mesh {vertices, indices, ..}) => {
pass.set_vertex_buffer(0, vertices.0.slice(..));
if let Some(indices) = indices {
pass.set_index_buffer(indices.0.slice(..), wgpu::IndexFormat::Uint32);
count = indices.1;
indexed = true;
} else {
count = vertices.1;
indexed = false;
}
}
Code::Draw(instances) => {
if indexed {
pass.draw_indexed(0..count, 0, instances)
} else {
pass.draw(0..count, instances);
}
}
}
}
}
}
impl Instances {
const MIN_SIZE: u64 = 64;
pub fn register_object(&mut self, mut object: RefId<ObjectData>) {
let model = object.model.as_mut().unwrap();
self.model_count += 1;
self.models
.entry(model.mesh.clone()).or_default()
.entry(model.material.clone()).or_default()
.insert(object.into(),self.models_flag);
}
/*pub fn register_light(&mut self, light: Id<LightData>) {
self.light_count += 1;
self.lights.insert(light);
}*/
pub fn reallocate_buffer(
device: &wgpu::Device,
buffer: &mut wgpu::Buffer,
count: usize,
item_size: usize,
) {
let size = buffer.size() / item_size as wgpu::BufferAddress;
if count > Instances::MIN_SIZE as usize {
let mut reallocate: Option<usize> = None;
if count < (size / 2) as usize {
reallocate = Some(count / 2);
} else if count > size as usize {
reallocate = Some(count * 2);
}
if let Some(new_size) = reallocate {
*buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Instance Buffer"),
size: (item_size * new_size) as wgpu::BufferAddress,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
}
}
}
/*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>());
/*
let mut light_ref_buffer = queue.write_buffer_with(
&self.light_ref_buffer,
0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
).unwrap();
*/
Instances::reallocate_buffer(
device,
&mut self.light_buffer,
self.light_count,
size_of::<WorldLight>(),
);
let mut buffer = queue
.write_buffer_with(
&self.light_buffer,
0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.light_buffer.size()).unwrap(),
)
.unwrap();
let stride = size_of::<WorldLight>();
for (new_index, (light, index)) in self.lights.iter_mut().enumerate() {
*index = new_index + 1;
let begin = *index * stride;
buffer
.slice(begin..begin + stride)
.copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
}
}*/
pub(crate) fn write_instances(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
mesh_list: &mut FreeList<Mesh>,
objects_list: &mut FreeList<ObjectData>,
) {
Instances::reallocate_buffer(
device,
&mut self.model_buffer,
self.model_count,
size_of::<ModelInstance>(),
);
let mut buffer = queue
.write_buffer_with(
&self.model_buffer,
0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.model_buffer.size()).unwrap(),
)
.unwrap();
let mut index: u32 = 0;
let stride = size_of::<ModelInstance>();
for (mesh, materials) in self.models.iter_mut() {
self.program.push(Code::Mesh(mesh_list.get(mesh).clone()));
for (material, objects) in materials.iter_mut() {
self.program.push(Code::Material(self.materials.list.get(material).clone()));
let before = index;
objects.retain(|object,flag| {
let object = objects_list.get(object);
if *flag == self.models_flag {
let begin = index as usize * stride;
buffer.slice(begin..begin + stride).copy_from_slice(bytemuck::cast_slice(&[object.model.as_mut().unwrap().instance]));
index += 1;
true
} else {
false
}
});
self.program.push(Code::Draw(before..index));
}
}
//println!("objects: {}",index);
self.models_flag = !self.models_flag;
}
pub(crate) fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: size_of::<ModelInstance>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &[
// todo: is this too big?
wgpu::VertexAttribute {
offset: 0,
shader_location: 4,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 4]>() as wgpu::BufferAddress,
shader_location: 5,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 8]>() as wgpu::BufferAddress,
shader_location: 6,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 12]>() as wgpu::BufferAddress,
shader_location: 7,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 16]>() as wgpu::BufferAddress,
shader_location: 8,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 16]>() as wgpu::BufferAddress,
shader_location: 9,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 16]>() as wgpu::BufferAddress,
shader_location: 10,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 16]>() as wgpu::BufferAddress,
shader_location: 11,
format: wgpu::VertexFormat::Float32x4,
},
],
}
}
pub fn new(device: &wgpu::Device, eye: &Eye, config: &wgpu::SurfaceConfiguration, default: Texture) -> Instances {
let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Instance Buffer"),
size: (size_of::<ModelInstance>() * Instances::MIN_SIZE as usize)
as wgpu::BufferAddress,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let light_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Light Buffer"),
size: (size_of::<LightInstance>() * Instances::MIN_SIZE as usize)
as wgpu::BufferAddress,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
/*let light_ref_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Light Ref Buffer"),
size: (size_of::<u32>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});*/
let materials = Materials::new(device, default);
let shader = device.create_shader_module(wgpu::include_wgsl!("instance.wgsl"));
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[Some(&eye.layout), Some(&materials.layout)],
immediate_size: 0,
});
let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[TangentVertex::desc(), Instances::desc()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
// 3.
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
// 4.
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: Default::default(), /*wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
}*/
depth_stencil: Some(wgpu::DepthStencilState {
stencil: wgpu::StencilState::default(),
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Less),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview_mask: None,
cache: None,
});
Instances {
materials,
light_instances: Default::default(),
model_instances: Default::default(),
pipeline: instance_pipeline,
light_count: 0,
//light_ref_last: 0,
model_count: 0,
light_buffer,
model_buffer: instance_buffer,
//light_ref_buffer,
//lights: Default::default(),
models_flag: false,
program: Program(Vec::new()),
models: Default::default(),
}
}
pub fn render() {
}
}

302
src/render/loader.rs Normal file
View file

@ -0,0 +1,302 @@
use std::collections::HashMap;
use glam::{Mat4, Vec3, Vec4};
use gltf::Semantic;
use wgpu::{Device, Queue};
use wgpu::util::DeviceExt;
use crate::list::{FreeList, Id, RefId};
use crate::render::instance::{Material, Materials, ModelData, ModelInstance};
use crate::render::instance::material::MaterialProperties;
use crate::render::mesh::{Mesh, TangentVertex};
use crate::render::texture::{Texture, TextureProperties};
use crate::render::{Renderer, Textures};
use crate::world::{ObjectData, AABB, ColliderData, Shape};
pub struct TreeNode {
object: Option<ObjectData>,
children: Vec<TreeNode>,
name: String,
}
impl TreeNode {
pub fn first_object(&self) -> Option<ObjectData> {
if let Some(object) = self.object.clone() {
Some(object)
} else {
for child in self.children.iter() {
if let Some(object) = child.first_object() {
return Some(object);
}
}
None
}
}
}
type GltfVertexBufferKey = (Option<usize>, Option<usize>, Option<usize>, Option<usize>);
pub fn new_texture_from_gltf(
device: &Device,
queue: &Queue,
info: &gltf::texture::Texture,
images: &Vec<gltf::image::Data>,
) -> Option<Texture> {
if let Some(image) = images.get(info.source().index()) {
let mut new_pixels = Vec::new();
let pixels: &Vec<u8>;
match image.format {
gltf::image::Format::R8G8B8 => {
for pixel in image.pixels.chunks(3) {
new_pixels.push(pixel[0]);
new_pixels.push(pixel[0]);
new_pixels.push(pixel[0]);
new_pixels.push(255);
}
pixels = &new_pixels;
}
gltf::image::Format::R8G8B8A8 => pixels = &image.pixels,
_ => return None,
}
Some(Texture::load(
device,
queue,
pixels.as_slice(),
TextureProperties {
width: image.width,
height: image.height,
},
))
} else {
None
}
}
pub fn new_mesh_from_gltf(
device: &Device,
primitive: gltf::Primitive,
meshes: &mut HashMap<GltfVertexBufferKey, Mesh>,
buffers: &[gltf::buffer::Data],
) -> Mesh {
let position_index = primitive
.get(&Semantic::Positions)
.and_then(|it| it.view()).map(|it| it.buffer().index());
let normals_index = primitive
.get(&Semantic::Normals)
.and_then(|it| it.view()).map(|it| it.buffer().index());
let tex_coords_index = primitive
.get(&Semantic::TexCoords(0))
.and_then(|it| it.view()).map(|it| it.buffer().index());
let indices_index = primitive
.indices()
.and_then(|it| it.view()).map(|it| it.buffer().index());
let tangent_index = primitive
.get(&Semantic::Tangents)
.and_then(|it| it.view()).map(|it| it.buffer().index());
let key = (
position_index,
normals_index,
tex_coords_index,
indices_index,
);
let insert = || {
let mut tangents = false;
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
let mut vertex_data: Vec<TangentVertex>;
let mut aabb = AABB(Vec3::ZERO,Vec3::ZERO);
if let Some(positions) = reader.read_positions() {
vertex_data = Vec::with_capacity(positions.len());
let mut normal = reader.read_normals().map(|it| it.into_iter());
let mut tex_coord = reader
.read_tex_coords(0)
.map(|it| it.into_f32().into_iter());
let mut tangent = reader.read_tangents().map(|it| it.into_iter());
tangents = tangent.is_some();
for position in positions {
aabb = aabb.extend_to(Vec3::from(position));
vertex_data.push(TangentVertex {
position,
normal: if let Some(ref mut normals) = normal {
if let Some(normal) = normals.next() {
normal
} else {
[0.0; 3]
}
} else {
[0.0; 3]
},
tex_coord: if let Some(ref mut tex_coords) = tex_coord {
tex_coords.next()
} else {
None
}
.unwrap_or([0.0; 2]),
tangent: [0.0; 3], // todo: tangent from model
bitangent: [0.0; 3],
})
}
} else {
vertex_data = Vec::new();
}
let vertex_buffer =
device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(vertex_data.as_slice()),
usage: wgpu::BufferUsages::VERTEX,
});
let vertices_result = (vertex_buffer, vertex_data.len() as u32);
let indices_result = if let Some(indices) = reader.read_indices() {
let index_data: Vec<u32> = indices.into_u32().collect();
Some((
device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(index_data.as_slice()),
usage: wgpu::BufferUsages::INDEX,
}),
index_data.len() as u32,
))
} else {
None
};
Mesh {
indices: indices_result,
vertices: vertices_result,
aabb,
}
};
meshes.entry(key).or_insert_with(insert).clone()
}
pub fn load_node_from_gltf(
node: gltf::Node,
device: &Device,
queue: &Queue,
mesh_map: &mut HashMap<GltfVertexBufferKey, Mesh>,
texture_map: &mut HashMap<usize, Texture>,
materials: &mut Materials,
textures: &Textures,
meshes: &mut FreeList<Mesh>,
images: &Vec<gltf::image::Data>,
buffers: &Vec<gltf::buffer::Data>,
) -> TreeNode {
let mut tree_node = TreeNode {
object: None,
children: Vec::new(),
name: node.name().unwrap_or("Node").to_string(),
};
if let Some(mesh) = node.mesh() {
let len = mesh.primitives().len();
for primitive in mesh.primitives() {
let pbr = primitive.material().pbr_metallic_roughness();
let material = primitive.material();
let color = pbr.base_color_factor();
let metal = pbr.metallic_factor();
let rough = pbr.roughness_factor();
let light = primitive.material().emissive_factor();
let base = match pbr.base_color_texture() {
Some(info) => texture_map
.entry(info.texture().source().index())
.or_insert_with(|| new_texture_from_gltf(device,queue,&info.texture(), &images).unwrap_or_else(|| textures.default.clone()))
.clone(),
None => textures.default.clone(),
};
let reflect = match pbr.metallic_roughness_texture() {
Some(info) => texture_map
.entry(info.texture().source().index())
.or_insert_with(|| new_texture_from_gltf(device,queue,&info.texture(), &images).unwrap_or_else(|| textures.default.clone()))
.clone(),
None => textures.default.clone(),
};
let normal = match material.normal_texture() {
Some(info) => texture_map
.entry(info.texture().source().index())
.or_insert_with(|| new_texture_from_gltf(device,queue,&info.texture(), &images).unwrap_or_else(|| textures.default.clone()))
.clone(),
None => textures.default.clone(),
};
let material = materials.list.make(Material::_new(
&device,
&materials.layout,
&base,
&normal,
&reflect,
MaterialProperties {
edge: wgpu::AddressMode::Repeat,
filter: wgpu::FilterMode::Linear,
},
)).into();;
let mesh = new_mesh_from_gltf(device, primitive, mesh_map, buffers);
let aabb = mesh.aabb;
let object = ObjectData {
model: Some(ModelData {
instance: ModelInstance {
transform: Mat4::default(),
color: Vec4::from_array(color),
lights: [0; 16],
point_lights: 0,
spot_lights: 0,
metal,
rough,
},
material,
mesh: meshes.make(mesh).id,
}),
collider: ColliderData { shape: Shape::Sphere(aabb.1.distance(aabb.0)) },
affine: Default::default(),
asleep: false,
};
if len == 1 {
tree_node.object = Some(object);
} else {
tree_node.children.push(TreeNode {
object: Some(object),
children: Vec::new(),
name: "Primitive".to_string(),
})
}
}
}
for node in node.children() {
tree_node
.children
.push(load_node_from_gltf(node, device, queue, mesh_map, texture_map, materials, textures, meshes, images, buffers));
}
tree_node
}
pub fn _load_from_gltf(device: &Device, queue: &Queue, meshes: &mut FreeList<Mesh>, materials: &mut Materials, textures: &mut Textures, slice: impl AsRef<[u8]>) -> TreeNode {
let mut root = TreeNode {
object: None,
children: Vec::new(),
name: "Root".to_string(),
};
if let Ok((document, buffers, images)) = gltf::import_slice(slice) {
let mut mesh_map: HashMap<GltfVertexBufferKey, Mesh> = HashMap::new();
let mut texture_map: HashMap<usize, Texture> = HashMap::new();
for scene in document.scenes() {
let mut scene_node = TreeNode {
object: None,
children: Vec::new(),
name: scene.name().unwrap_or("Scene").to_string(),
};
for node in scene.nodes() {
scene_node.children.push(load_node_from_gltf(
node,
device,
queue,
&mut mesh_map,
&mut texture_map,
materials,
textures,
meshes,
&images,
&buffers,
));
}
root.children.push(scene_node)
}
}
root
}
pub fn load_from_gltf(renderer: &mut Renderer, slice: impl AsRef<[u8]>) -> TreeNode {
_load_from_gltf(&renderer.device, &renderer.queue, &mut renderer.meshes, &mut renderer.instances.materials, &mut renderer.textures, slice)
}

51
src/render/mesh.rs Normal file
View file

@ -0,0 +1,51 @@
use crate::world::AABB;
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct TangentVertex {
pub(crate) position: [f32; 3],
pub(crate) normal: [f32; 3],
pub(crate) tex_coord: [f32; 2],
pub(crate) tangent: [f32; 3],
pub(crate) bitangent: [f32; 3],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
position: [f32; 3],
normal: [f32; 3],
tex_coord: [f32; 3],
}
impl TangentVertex {
pub(crate) fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: size_of::<TangentVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 1,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: size_of::<[f32; 6]>() as wgpu::BufferAddress,
shader_location: 2,
format: wgpu::VertexFormat::Float32x2,
},
],
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Mesh {
pub(crate) indices: Option<(wgpu::Buffer, u32)>,
pub(crate) vertices: (wgpu::Buffer, u32),
pub(crate) aabb: AABB,
}

File diff suppressed because it is too large Load diff

72
src/render/sky.wgsl Normal file
View file

@ -0,0 +1,72 @@
struct Environment {
ambient: vec4<f32>,
light: vec4<f32>,
dir: vec4<f32>,
}
struct Eye {
// from camera to screen
proj: mat4x4<f32>,
// from screen to camera
inv: mat4x4<f32>,
// world to camera
view: mat4x4<f32>,
// camera transform
frame: mat4x4<f32>,
}
@group(0) @binding(0)
var<uniform> eye: Eye;
@group(0) @binding(1)
var<uniform> environment: Environment;
@group(0) @binding(2)
var sky_sampler: sampler;
@group(0) @binding(3)
var sky_texture: texture_2d<f32>;
// written on the 60th sleepless hour
fn sky_aspect(look: vec3<f32>) -> vec4<f32> {
var pi = 3.14159;
let u_angle = atan2(look.x,look.z);
let u = (u_angle/pi) * 0.5 + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
let v_angle = atan2(-look.y,sqrt(look.x * look.x + look.z * look.z));
let v = (v_angle/pi) - 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1
let uv = vec2<f32>(u,v); // Get UV on skybox
return textureSample(sky_texture, sky_sampler, uv);
}
struct SkyOutput {
@builtin(position) position: vec4<f32>,
@location(0) pos: vec4<f32> // unadulterated by WGSL
}
const VERTICES = array(
vec4(-1.0, -1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
vec4( 1.0, 1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
);
fn rotation(it: mat4x4<f32>) -> mat3x3<f32> {
return mat3x3<f32>(
it[0].xyz,
it[1].xyz,
it[2].xyz,
);
}
@vertex
fn vs_sky(@builtin(vertex_index) index: u32) -> SkyOutput {
var out: SkyOutput;
out.position = VERTICES[index];
out.pos = out.position;
return out;
}
@fragment
fn fs_sky(in: SkyOutput) -> @location(0) vec4<f32> {
let look = rotation(eye.frame) * in.pos.xyz;
return sky_aspect(look);
}

115
src/render/texture.rs Normal file
View file

@ -0,0 +1,115 @@
use image::EncodableLayout;
use wgpu::{Device, Queue};
use crate::render::Renderer;
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Texture {
texture: wgpu::Texture,
pub(crate) view: wgpu::TextureView,
}
pub struct TextureProperties {
pub(crate) width: u32,
pub(crate) height: u32,
}
// todo: use texture compression!
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(
device: &Device,
queue: &Queue,
slice: impl AsRef<[u8]>,
properties: TextureProperties,
) -> Texture {
let size = wgpu::Extent3d {
width: properties.width,
height: properties.height,
depth_or_array_layers: 1,
};
let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor {
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: Some("texture"),
view_formats: &[],
});
let diffuse_texture_view =
diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &diffuse_texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
slice.as_ref(),
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4 * size.width),
rows_per_image: Some(size.height),
},
size,
);
Texture {
texture: diffuse_texture,
view: diffuse_texture_view,
}
}
fn _load_from_file_bytes(
device: &Device,
queue: &Queue,
slice: impl AsRef<[u8]>,
format: Option<image::ImageFormat>,
) -> Option<Texture> {
let image = if let Some(format) = format {
image::load_from_memory_with_format(slice.as_ref(), format)
} else {
image::load_from_memory(slice.as_ref())
};
if let Ok(data) = image {
let data = data.into_rgba8();
Some(Texture::load(
device,
queue,
data.as_bytes(),
TextureProperties {
width: data.width(),
height: data.height(),
},
))
} else {
println!("failed to load texture! error: {:?}", image.unwrap_err());
None
}
}
pub fn load_from_file_bytes(renderer: &mut Renderer, slice: impl AsRef<[u8]>, format: Option<image::ImageFormat>) -> Option<Texture> {
Texture::_load_from_file_bytes(&renderer.device,&renderer.queue,slice,format)
}
}

View file

@ -4,7 +4,7 @@ use crate::{render, world};
#[derive(Default)]
pub struct State {
pub objects: FreeList<world::ObjectData>,
pub lights: FreeList<render::LightData>,
pub lights: FreeList<render::instance::LightData>,
pub worlds: FreeList<world::World>,
pub renderer: Option<render::Renderer>,
pub screens: FreeList<render::Screen>

100
src/world/debug.rs Normal file
View file

@ -0,0 +1,100 @@
use glam::{IVec3, Mat4, Quat, Vec3};
use wgpu::naga::FastHashMap;
use crate::list::{FreeList, Id};
use crate::render;
use crate::world::{ColliderData, ObjectData, OctreeBlock, Shape, World};
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::instance::ModelData>,
pos: IVec3,
mut 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());
}
}
size /= 2;
if let Some(block) = blocks.get(&block).blocks[0].exists() {
self.set_block(blocks,block,objects,debug, pos - (IVec3::new(-1, -1, -1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[1].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,-1,-1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[2].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,1,-1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[3].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,1,-1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[4].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,-1,1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[5].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,-1,1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[6].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(-1,1,1) * size / 2), size);
}
if let Some(block) = blocks.get(&block).blocks[7].exists() {
self.set_block(blocks,block,objects,debug,pos - (IVec3::new(1,1,1) * size / 2), size);
}
}
pub fn set(&mut self, objects: &mut FreeList<ObjectData>, world: &mut World, debug: Option<render::instance::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()));
}
}
}

View file

@ -1,3 +1,6 @@
pub mod debug;
use crate::render::instance::ModelData;
use glam::{Affine3, IVec3, Mat4, Quat, Vec3};
use std::cell::RefCell;
use std::hash::{BuildHasherDefault, Hash, Hasher};
@ -43,15 +46,22 @@ impl ColliderData {
#[derive(Clone)]
pub struct ObjectData {
pub model: Option<render::ModelData>,
pub model: Option<render::instance::ModelData>,
pub collider: ColliderData,
pub affine: Affine3,
pub asleep: bool,
}
impl ObjectData {
pub fn set_affine(&mut self, affine: Affine3) {
self.affine = affine;
self.asleep = false;
}
}
#[derive(Clone, Eq, PartialEq)]
pub enum InterestType {
Light(Id<render::LightData>),
Light(Id<render::instance::LightData>),
Object(Id<ObjectData>)
}
@ -119,100 +129,6 @@ impl Default for World {
}
}
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 World {
pub fn new() -> World {
World {
@ -234,9 +150,9 @@ impl World {
&mut self,
maybe_renderer: &mut Option<render::Renderer>,
objects: &mut FreeList<ObjectData>,
_lights: &mut FreeList<render::LightData>,
_lights: &mut FreeList<render::instance::LightData>,
) {
/*fn reinsert(
fn reinsert(
block_id: &Id<OctreeBlock>,
blocks: &mut FreeList<OctreeBlock>,
interests: &mut FreeList<InterestNode>,
@ -247,10 +163,6 @@ impl World {
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;
instances.register_object(object)
}
_ => {}
}
@ -263,8 +175,8 @@ impl World {
}
}
for (_pos,id) in self.matter.map.iter() {
reinsert(id, &mut self.matter.blocks, &mut self.matter.interests, objects)
}*/
reinsert(id, &mut self.matter.blocks, &mut self.matter.nodes, objects)
}
if let Some(renderer) = maybe_renderer {
fn consider(
block_id: &Id<OctreeBlock>,
@ -294,7 +206,7 @@ impl World {
}
}
for (_pos,id) in self.matter.map.iter() {
consider(id, renderer, &mut self.matter.blocks, &mut self.matter.interests, objects)
consider(id, renderer, &mut self.matter.blocks, &mut self.matter.nodes, objects)
}
}
}
@ -340,14 +252,14 @@ struct OctreeBlock {
}
impl OctreeBlock {
fn push(&mut self, interests: &mut FreeList<InterestNode>, interest: Interest) {
fn push_interest(&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) {
fn remove_interest(&mut self, interests: &mut FreeList<InterestNode>, needle: Interest) { // todo: needed?
let mut maybe_last = MaybeId::NULL;
let mut maybe_this = self.first.clone();
while let Some(this) = maybe_this.exists() {
@ -376,7 +288,7 @@ impl OctreeBlock {
size: i32,
) {
if pos == IVec3::ZERO || blocks.get(&it).interests < OctreeBlock::MAX_IDEAL_INTEREST as u32 {
blocks.get(&it).push(interests,interest)
blocks.get(&it).push_interest(interests, interest)
} else {
let mut index = 0;
let x = if pos.x > 0 {
@ -413,8 +325,9 @@ impl OctreeBlock {
type Blocks = [MaybeId<OctreeBlock>; 8];
struct OctreeMap {
interests: FreeList<InterestNode>,
pub struct OctreeMap {
interests: FreeList<Interest>,
nodes: FreeList<InterestNode>,
blocks: FreeList<OctreeBlock>,
map: FastHashMap<IVec3, Id<OctreeBlock>>,
}
@ -446,7 +359,7 @@ impl OctreeMap {
OctreeBlock::place(
block.clone(),
&mut self.blocks,
&mut self.interests,
&mut self.nodes,
interest.clone(),
pos,
OctreeBlock::CHUNK_SIZE,
@ -458,6 +371,7 @@ impl OctreeMap {
fn new() -> OctreeMap {
OctreeMap {
interests: Default::default(),
nodes: Default::default(),
blocks: Default::default(),
map: FastHashMap::with_hasher(BuildHasherDefault::default()),
}