feat: added the beginnings of a ecs based camera system. render_scene_2d crashes miserably right now but theoretically everything *should* be in place for a full adoption

This commit is contained in:
lisk77 2025-02-26 23:53:52 +01:00
parent a9a8d076ca
commit 4ce24b58dd
5 changed files with 128 additions and 33 deletions

View file

@ -4,7 +4,7 @@ use std::sync::atomic::AtomicBool;
use std::thread;
use std::time::{Duration, Instant};
use crossbeam_channel::bounded;
use comet_ecs::{Component, ComponentSet, Entity, Render, Transform2D, Transform3D, World};
use comet_ecs::{Camera2D, Component, ComponentSet, Entity, Render, Render2D, Transform2D, Transform3D, World};
use comet_resources::{ResourceManager, Vertex};
use comet_renderer::renderer2d::Renderer2D;
@ -98,7 +98,9 @@ impl App {
match preset {
ApplicationType::App2D => {
info!("Creating 2D app!");
self.world.register_component::<Transform2D>()
self.world.register_component::<Transform2D>();
self.world.register_component::<Render2D>();
self.world.register_component::<Camera2D>()
},
ApplicationType::App3D => {
info!("Creating 3D app!");
@ -129,8 +131,8 @@ impl App {
self.game_state.as_mut()?.downcast_mut::<T>()
}
pub fn input_manager(&self) -> &WinitInputHelper {
&self.input_manager
pub fn world(&self) -> &World {
&self.world
}
pub fn key_pressed(&self, key: Key) -> bool {

View file

@ -3,12 +3,13 @@
// Also just as a nomenclature: bundles are a component made up of multiple components,
// so it's a collection of components bundled together (like Transform2D)
use comet_math::Mat4;
use crate::math::{
Vec2,
Vec3
};
use component_derive::Component;
use crate::Entity;
use crate::{Entity, World};
// ##################################################
// # BASIC #
@ -51,13 +52,8 @@ pub struct Render2D {
#[derive(Component)]
pub struct Camera2D {
left: f32,
right: f32,
bottom: f32,
top: f32,
near: f32,
far: f32,
zoom: f32
zoom: f32,
dimensions: Vec2,
}
// ##################################################
@ -104,7 +100,8 @@ pub trait Render {
}
pub trait Camera {
fn get_visible_entities(&self) -> Vec<Entity>;
fn get_visible_entities(&self, camera_position: Position2D, world: World) -> Vec<Entity>;
fn get_projection_matrix(&self) -> Mat4;
}
// ##################################################
@ -278,18 +275,29 @@ impl Transform3D {
}
impl Camera2D {
pub fn new(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32, zoom: f32) -> Self {
pub fn new(dimensions: Vec2, zoom: f32) -> Self {
Self {
left,
right,
bottom,
top,
near,
far,
dimensions,
zoom
}
}
pub fn zoom(&self) -> f32 {
self.zoom
}
pub fn set_zoom(&mut self, zoom: f32) {
self.zoom = zoom;
}
pub fn dimensions(&self) -> Vec2 {
self.dimensions
}
pub fn set_dimensions(&mut self, dimensions: Vec2) {
self.dimensions = dimensions;
}
fn in_view_frustum(&self, camera_pos: Position2D, entity: Position2D) -> bool {
let left = camera_pos.x() - self.zoom;
let right = camera_pos.x() + self.zoom;
@ -301,7 +309,23 @@ impl Camera2D {
}
impl Camera for Camera2D {
fn get_visible_entities(&self) -> Vec<Entity> {
unimplemented!()
fn get_visible_entities(&self, camera_position: Position2D, world: World) -> Vec<Entity> {
let entities = world.entities();
let mut visible_entities = Vec::new();
for entity in entities {
if self.in_view_frustum(camera_position, *world.get_component::<Transform2D>(*entity.clone().unwrap().id() as usize).unwrap().position()) {
visible_entities.push(entity.clone().unwrap());
}
}
visible_entities
}
fn get_projection_matrix(&self) -> Mat4 {
let left = -self.dimensions.x() / 2.0;
let right = self.dimensions.x() / 2.0;
let bottom = -self.dimensions.y() / 2.0;
let top = self.dimensions.y() / 2.0;
Mat4::OPENGL * Mat4::orthographic_matrix(left, right, bottom, top, 1.0, 0.0)
}
}

View file

@ -200,7 +200,10 @@ impl World {
/// Returns a list of entities that have the given components.
pub fn get_entities_with(&self, components: ComponentSet) -> Vec<u32> {
assert!(self.archetypes.contains_archetype(&components), "The given components {:?} are not registered in the world!", components);
self.archetypes.get_archetype(&components).unwrap().clone()
//assert!(self.archetypes.contains_archetype(&components), "The given components {:?} are not registered in the world!", components);
if self.archetypes.contains_archetype(&components) {
return self.archetypes.get_archetype(&components).unwrap().clone();
}
Vec::new()
}
}

View file

@ -528,6 +528,13 @@ impl Mat4 {
x30: 0.0, x31: 0.0, x32: 0.0, x33: 1.0
};
pub const OPENGL: Mat4 = Mat4 {
x00: 1.0, x01: 0.0, x02: 0.0, x03: 0.0,
x10: 0.0, x11: 1.0, x12: 0.0, x13: 0.0,
x20: 0.0, x21: 0.0, x22: 0.5, x23: 0.0,
x30: 0.0, x31: 0.0, x32: 0.5, x33: 1.0
};
pub const fn new(x00: f32, x01: f32,x02: f32,x03: f32,x10: f32,x11: f32,x12: f32,x13: f32,x20: f32,x21: f32,x22: f32,x23: f32,x30: f32, x31: f32, x32: f32,x33: f32) -> Self {
Self {
x00, x01, x02, x03,

View file

@ -8,12 +8,12 @@ use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;
use winit::window::Window;
use comet_colors::LinearRgba;
use comet_ecs::{Component, ComponentSet, Render, Render2D, Transform2D, World};
use comet_ecs::{Camera, Camera2D, Component, ComponentSet, Render, Render2D, Transform2D, World};
use comet_log::{debug, info};
use comet_math::{Point3, Vec2, Vec3};
use comet_resources::{texture, graphic_resource_manager::GraphicResorceManager, Texture, Vertex};
use comet_resources::texture_atlas::TextureRegion;
use crate::camera::{Camera, CameraUniform};
use crate::camera::{Camera as OldCam, CameraUniform};
use crate::render_pass::RenderPassInfo;
use crate::renderer::Renderer;
@ -37,7 +37,7 @@ pub struct Renderer2D<'a> {
diffuse_texture: texture::Texture,
diffuse_bind_group: wgpu::BindGroup,
graphic_resource_manager: GraphicResorceManager,
camera: Camera,
camera: OldCam,
camera_uniform: CameraUniform,
camera_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup,
@ -120,7 +120,7 @@ impl<'a> Renderer2D<'a> {
let diffuse_bytes = include_bytes!(r"../../../resources/textures/comet_icon.png");
let diffuse_texture =
texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "comet_icon.png", false).unwrap();
Texture::from_bytes(&device, &queue, diffuse_bytes, "comet_icon.png", false).unwrap();
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -160,7 +160,7 @@ impl<'a> Renderer2D<'a> {
label: Some("diffuse_bind_group"),
});
let camera = Camera::new(1.0, Vec2::new(2.0, 2.0), Vec3::new(0.0, 0.0, 0.0));
let camera = OldCam::new(1.0, Vec2::new(2.0, 2.0), Vec3::new(0.0, 0.0, 0.0));
let mut camera_uniform = CameraUniform::new();
camera_uniform.update_view_proj(&camera);
@ -288,9 +288,9 @@ impl<'a> Renderer2D<'a> {
diffuse_bind_group,
graphic_resource_manager,
camera,
camera_uniform,
camera_buffer,
camera_bind_group,
camera_uniform,
camera_bind_group
}
}
@ -732,7 +732,66 @@ impl<'a> Renderer2D<'a> {
/// A function to automatically render all the entities of the `World` struct.
/// The entities must have the `Render2D` and `Transform2D` components to be rendered as well as set visible.
pub fn render_scene_2d(&mut self, world: &World) {
let entities = world.get_entities_with(ComponentSet::from_ids(vec![Render2D::type_id()]));
let cameras = world.get_entities_with(ComponentSet::from_ids(vec![Camera2D::type_id()]));
if cameras == vec![] {
info!("No camera found in the scene");
return;
}
info!("Camera found in the scene");
let entities = world.get_entities_with(ComponentSet::from_ids(vec![Transform2D::type_id(), Render2D::type_id()]));
for camera in cameras {
let camera_position = world.get_component::<Transform2D>(camera as usize).unwrap().position();
let camera_component = world.get_component::<Camera2D>(camera as usize);
let camera = OldCam::new(camera_component.unwrap().zoom(), camera_component.unwrap().dimensions(), Vec3::new(camera_position.as_vec().x(), camera_position.as_vec().y(), 0.0));
let mut camera_uniform = CameraUniform::new();
camera_uniform.update_view_proj(&camera);
let camera_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[camera_uniform]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let camera_bind_group_layout =
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
label: Some("camera_bind_group_layout"),
});
let camera_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &camera_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: camera_buffer.as_entire_binding(),
}],
label: Some("camera_bind_group"),
});
self.camera = camera;
self.camera_buffer = camera_buffer;
self.camera_uniform = camera_uniform;
self.camera_bind_group = camera_bind_group;
let visible_entities = camera_component.unwrap().get_visible_entities(*camera_position, world.clone());
println!("{:?}", visible_entities);
}
/*let entities = world.get_entities_with(ComponentSet::from_ids(vec![Transform2D::type_id(), Render2D::type_id()]));
let mut vertex_buffer: Vec<Vertex> = Vec::new();
let mut index_buffer: Vec<u16> = Vec::new();
@ -767,7 +826,7 @@ impl<'a> Renderer2D<'a> {
}
}
self.set_buffers(vertex_buffer, index_buffer);
self.set_buffers(vertex_buffer, index_buffer);*/
}
pub fn update(&mut self) -> f32 {