Giant refactor for a better event-driven architecture
This commit is contained in:
parent
341d531db3
commit
88a21040cd
22 changed files with 936 additions and 67 deletions
|
|
@ -11,5 +11,6 @@ gltf = { version = "1.4.1", features = ["import", "utils", "KHR_texture_transf
|
|||
glutin = { version = "0.32.3", default-features = false }
|
||||
hecs = "0.10.5"
|
||||
image = "0.25.6"
|
||||
raidillon_core = { path = "../raidillon_core" }
|
||||
raidillon_ecs = { path = "../raidillon_ecs" }
|
||||
winit = "0.30"
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@ pub mod model;
|
|||
pub mod gltf_loader;
|
||||
pub mod render;
|
||||
pub mod ecs_renderer;
|
||||
pub mod render_system;
|
||||
pub mod window;
|
||||
|
||||
pub use camera::Camera;
|
||||
pub use render::GliumRenderer;
|
||||
pub use ecs_renderer::ECSRenderer;
|
||||
pub use render_system::RenderSystem;
|
||||
pub use raidillon_core::ModelId;
|
||||
pub use window::{DisplayHandle, init_window as init_render_window};
|
||||
|
|
|
|||
|
|
@ -51,7 +51,13 @@ impl Default for Material {
|
|||
}
|
||||
}
|
||||
|
||||
// Implement the Material trait from raidillon_core
|
||||
impl raidillon_core::Material for Material {}
|
||||
|
||||
pub struct Model {
|
||||
pub mesh: Mesh,
|
||||
pub material: Material,
|
||||
}
|
||||
|
||||
// Implement the Model trait from raidillon_core
|
||||
impl raidillon_core::Model for Model {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::camera::Camera;
|
||||
use raidillon_ecs::{ModelHandle, Transform};
|
||||
use crate::model::{Model, Mesh};
|
||||
use crate::model::{Model, Material, Mesh};
|
||||
use raidillon_core::AssetManager;
|
||||
use glium::texture::{RawImage2d, SrgbTexture2d};
|
||||
use glium::{uniform, Program, Surface};
|
||||
use glium::uniforms::{MinifySamplerFilter, MagnifySamplerFilter, SamplerWrapFunction};
|
||||
|
|
@ -164,4 +165,94 @@ impl GliumRenderer {
|
|||
pub fn display(&self) -> &glium::Display<WindowSurface> {
|
||||
&self.display
|
||||
}
|
||||
|
||||
pub fn render_into_with_assets<S: Surface>(&mut self, world: &World, assets: &AssetManager<Model, Material>, target: &mut S) {
|
||||
target.clear_color_and_depth((0.1, 0.1, 0.15, 1.0), 1.0);
|
||||
self.draw_scene_with_assets(world, assets, target);
|
||||
}
|
||||
|
||||
fn draw_scene_with_assets<S: Surface>(&mut self, world: &World, assets: &AssetManager<Model, Material>, target: &mut S) {
|
||||
let cam = match world.query::<&Camera>().iter().next() {
|
||||
Some((_, cam)) => *cam,
|
||||
None => {
|
||||
eprintln!("[renderer] No camera component found. Skipping frame");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Direction from the light source (0,+Y) towards the scene.
|
||||
let light_dir: Vec3 = Vec3::new(0.0, -1.0, 0.0).normalize();
|
||||
|
||||
for (_, (tr, mh)) in world.query::<(&Transform, &ModelHandle)>().iter() {
|
||||
let model = match assets.get_model(raidillon_core::ModelId(mh.0)) {
|
||||
Some(model) => model,
|
||||
None => {
|
||||
eprintln!("[renderer] Model with ID {} not found in assets", mh.0);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let mesh = &model.mesh;
|
||||
let mat = &model.material;
|
||||
|
||||
let tex_ref: &SrgbTexture2d = mat.base_color.as_ref().unwrap_or(&self.white_tex);
|
||||
|
||||
let mut sampler = tex_ref.sampled();
|
||||
sampler = sampler.wrap_function(SamplerWrapFunction::Repeat);
|
||||
sampler = sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
sampler = sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
|
||||
let c = mat.base_color_factor;
|
||||
|
||||
let uniforms = uniform! {
|
||||
model: tr.matrix().to_cols_array_2d(),
|
||||
view: cam.view().to_cols_array_2d(),
|
||||
projection: cam.projection().to_cols_array_2d(),
|
||||
u_light: [light_dir.x, light_dir.y, light_dir.z],
|
||||
tex: sampler,
|
||||
color: [c[0], c[1], c[2]],
|
||||
uv_offset: [mat.uv_offset.x, mat.uv_offset.y],
|
||||
uv_scale: [mat.uv_scale.x, mat.uv_scale.y],
|
||||
};
|
||||
|
||||
target.draw(
|
||||
&mesh.vbuf,
|
||||
&mesh.ibuf,
|
||||
&self.program,
|
||||
&uniforms,
|
||||
&self.params,
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
// Render skybox
|
||||
let mut sky_view = cam.view();
|
||||
sky_view.w_axis = Vec4::new(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
let mut sampler = self.skybox_texture.sampled();
|
||||
sampler = sampler.wrap_function(SamplerWrapFunction::Clamp);
|
||||
sampler = sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
sampler = sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
|
||||
let uniforms = uniform! {
|
||||
view: sky_view.to_cols_array_2d(),
|
||||
projection: cam.projection().to_cols_array_2d(),
|
||||
equirect: sampler,
|
||||
};
|
||||
|
||||
let sky_params = glium::DrawParameters {
|
||||
depth: glium::Depth {
|
||||
test: DepthTest::IfLessOrEqual,
|
||||
write: false,
|
||||
.. Default::default()
|
||||
},
|
||||
.. Default::default()
|
||||
};
|
||||
|
||||
target.draw(
|
||||
&self.skybox_mesh.vbuf,
|
||||
&self.skybox_mesh.ibuf,
|
||||
&self.skybox_program,
|
||||
&uniforms,
|
||||
&sky_params,
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
raidillon_render/src/render_system.rs
Normal file
50
raidillon_render/src/render_system.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use hecs::World;
|
||||
use raidillon_core::{AssetManager, ModelId};
|
||||
use crate::render::GliumRenderer;
|
||||
use crate::model::{Model, Material};
|
||||
use crate::window::DisplayHandle;
|
||||
use glium::Surface;
|
||||
|
||||
/// A pure render system that doesn't own the ECS world.
|
||||
/// This decouples rendering from ECS world ownership.
|
||||
pub struct RenderSystem {
|
||||
renderer: GliumRenderer,
|
||||
assets: AssetManager<Model, Material>,
|
||||
}
|
||||
|
||||
impl RenderSystem {
|
||||
pub fn new(display: DisplayHandle) -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
renderer: GliumRenderer::new(display.as_inner().clone())?,
|
||||
assets: AssetManager::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self, world: &World, target: &mut impl Surface) {
|
||||
// Pass the asset manager to the renderer for accessing models
|
||||
self.renderer.render_into_with_assets(world, &self.assets, target);
|
||||
}
|
||||
|
||||
pub fn load_model(&mut self, path: &str) -> anyhow::Result<ModelId> {
|
||||
// Check cache first
|
||||
let model = crate::gltf_loader::load_gltf(path, self.renderer.display())?;
|
||||
let model_id = self.assets.cache_model(path.to_string(), Box::new(model));
|
||||
Ok(model_id)
|
||||
}
|
||||
|
||||
pub fn display(&self) -> &glium::Display<glium::glutin::surface::WindowSurface> {
|
||||
self.renderer.display()
|
||||
}
|
||||
|
||||
pub fn get_model(&self, id: ModelId) -> Option<&Model> {
|
||||
self.assets.get_model(id)
|
||||
}
|
||||
|
||||
pub fn assets(&self) -> &AssetManager<Model, Material> {
|
||||
&self.assets
|
||||
}
|
||||
|
||||
pub fn assets_mut(&mut self) -> &mut AssetManager<Model, Material> {
|
||||
&mut self.assets
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue