Skip to content

Commit

Permalink
Merge pull request #6 from XavierCS-dev/Camera2D
Browse files Browse the repository at this point in the history
Camera 2D
  • Loading branch information
XavierCS-dev authored Mar 11, 2024
2 parents e7daf27 + 420dae3 commit bbbb220
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 30 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
- [ ] Increase unit test friendliness
- [ ] Hide main loop from user, or at least, make it easier to use
- [ ] Event System
- [ ] Provide a method to set a background image

- [ ] Further goals (0.2.0 release blockers)
- [ ] Implement Transformation2D
- [ ] Implement Camera2D (using 3D proj matrix)
- [x] Further goals (0.2.0 release blockers)
- [x] Implement Transformation2D
- [x] Implement Camera2D (using 3D proj matrix)

- [ ] Possible 0.3.0 release
- [ ] Sound system
Expand Down
109 changes: 109 additions & 0 deletions src/engine/camera/camera.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use wgpu::{util::DeviceExt, Queue};

use crate::engine::{
primitives::{matrix::Matrix4, vector::Vector3},
transform::transform::{Transform2D, Transform2DSystem},
};

pub struct Camera2D {
proj_mat: Matrix4,
complete_matrix: Matrix4,
transform: Transform2D,
near: f32,
far: f32,
fov_deg: f32,
bind_group: wgpu::BindGroup,
bind_group_layout: wgpu::BindGroupLayout,
buffer: wgpu::Buffer,
}

impl Camera2D {
pub fn new(device: &wgpu::Device, fov_deg: f32, aspect_ratio: f32) -> Self {
let near = 0.01;
let far = 10.0;
let fov_rad = fov_deg.to_radians();
let proj_mat = Matrix4::from_slice([
[1.0 / (aspect_ratio * (fov_rad / 2.0).tan()), 0.0, 0.0, 0.0],
[0.0, 1.0 / ((fov_rad / 2.0).tan()), 0.0, 0.0],
[0.0, 0.0, far / (far - near), -(far * near) / (far - near)],
[0.0, 0.0, 0.0, 1.0],
]);
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera"),
contents: bytemuck::cast_slice(&[proj_mat]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
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,
}],
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
}],
});
let transform = Transform2D::new();
let complete_matrix = Matrix4::new();
Self {
proj_mat,
near,
far,
fov_deg,
buffer,
bind_group,
bind_group_layout,
transform,
complete_matrix,
}
}

pub fn to_raw(&self) -> [[f32; 4]; 4] {
self.proj_mat.inner
}

pub fn buffer(&self) -> wgpu::BufferSlice {
self.buffer.slice(..)
}

pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}

pub fn bind_group_layout(&self) -> &wgpu::BindGroupLayout {
&self.bind_group_layout
}
}

pub struct Camera2DSystem;

impl Camera2DSystem {
pub fn transform(camera: &mut Camera2D, position: Vector3) {
let position = Vector3::new(-position.x, -position.y, position.z);
Transform2DSystem::translate(&mut camera.transform, position);
}

pub fn rotate(camera: &mut Camera2D, degrees: f32) {
Transform2DSystem::rotate(&mut camera.transform, degrees);
}

pub fn update(camera: &mut Camera2D, queue: &wgpu::Queue) {
camera.complete_matrix = camera.proj_mat * camera.transform.to_raw();
queue.write_buffer(
&camera.buffer,
0,
bytemuck::cast_slice(&camera.complete_matrix.inner),
);
}
}
1 change: 1 addition & 0 deletions src/engine/camera/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod camera;
28 changes: 25 additions & 3 deletions src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::engine::layer::layer::*;
use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;

use super::camera::camera::Camera2D;
use super::camera::camera::Camera2DSystem;
use super::primitives::vector::Vector3;
use super::{
primitives::vertex::Vertex,
Expand All @@ -23,14 +25,15 @@ pub struct Engine {
window: Arc<winit::window::Window>,
render_pipeline: wgpu::RenderPipeline,
texture_bgl: wgpu::BindGroupLayout,
camera: Camera2D,
}

/*
* Update and input should run closures defined by the user
* these closures are to be stored in Engine upon initialisation
*/
impl Engine {
pub async fn new(window: winit::window::Window) -> Self {
pub async fn new(window: winit::window::Window, camera_fov: f32) -> Self {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
..Default::default()
Expand All @@ -56,7 +59,12 @@ impl Engine {
)
.await
.unwrap();

let dims = window.inner_size();
let camera = Camera2D::new(
&device,
camera_fov,
(dims.width as f32) / (dims.height as f32),
);
let surface_capabilities = surface.get_capabilities(&adapter);
// Check this...may need to specifically set it to some sRGB value
let surface_format = surface_capabilities.formats[0];
Expand Down Expand Up @@ -100,7 +108,7 @@ impl Engine {
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Pipeline layout descriptor"),
bind_group_layouts: &[&texture_bgl],
bind_group_layouts: &[&texture_bgl, camera.bind_group_layout()],
push_constant_ranges: &[],
});

Expand Down Expand Up @@ -147,6 +155,7 @@ impl Engine {
window,
render_pipeline,
texture_bgl,
camera,
}
}

Expand Down Expand Up @@ -204,6 +213,7 @@ impl Engine {
render_pass.set_pipeline(&self.render_pipeline);
for layer in entities {
render_pass.set_bind_group(0, layer.bind_group(), &[]);
render_pass.set_bind_group(1, self.camera.bind_group(), &[]);
render_pass.set_vertex_buffer(0, layer.vertex_buffer());
render_pass.set_vertex_buffer(1, layer.entity_buffer().unwrap());
render_pass.set_index_buffer(layer.index_buffer(), wgpu::IndexFormat::Uint16);
Expand Down Expand Up @@ -257,4 +267,16 @@ impl Engine {
pub fn set_entities(&self, layer: &mut Layer2D, entities: &[&Entity2D]) {
Layer2DSystem::set_entities(layer, entities, &self.device, &self.queue)
}

pub fn update_camera(&mut self) {
Camera2DSystem::update(&mut self.camera, &self.queue);
}

pub fn camera(&self) -> &Camera2D {
&self.camera
}

pub fn camera_mut(&mut self) -> &mut Camera2D {
&mut self.camera
}
}
2 changes: 1 addition & 1 deletion src/engine/entity/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Entity2D {
// will include "model" with pos and rotation later...
pub fn to_raw(&self) -> Entity2DRaw {
Entity2DRaw {
transform: self.transform.to_raw(),
transform: self.transform.to_raw().inner,
texture_index: [self.texture_index[0] as f32, self.texture_index[1] as f32],
texture_size: self.texture_size.into(),
}
Expand Down
9 changes: 4 additions & 5 deletions src/engine/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
pub mod camera;
pub mod engine;
pub mod entity;
pub mod layer;
pub mod primitives;
pub mod texture;
pub mod traits;
pub mod layer;
pub mod util;
pub mod entity;

pub mod transform;

pub mod util;
17 changes: 17 additions & 0 deletions src/engine/primitives/matrix.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::ops::Mul;

#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Matrix4 {
Expand All @@ -20,3 +22,18 @@ impl Matrix4 {
Self { inner: mat_slice }
}
}

impl Mul for Matrix4 {
type Output = Matrix4;
fn mul(self, rhs: Self) -> Self::Output {
let mut new_mat = Matrix4::new();
for i in 0..4 {
for j in 0..4 {
for k in 0..4 {
new_mat.inner[i][j] += rhs.inner[k][j] * self.inner[i][k];
}
}
}
new_mat
}
}
4 changes: 2 additions & 2 deletions src/engine/transform/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ impl Transform2D {
}
}

pub fn to_raw(&self) -> [[f32; 4]; 4] {
self.matrix.inner
pub fn to_raw(&self) -> Matrix4 {
self.matrix
}

pub fn position(&self) -> &Vector3 {
Expand Down
26 changes: 17 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod engine;
use anyhow::Result;
use engine::{
camera::{self, camera::Camera2D},
engine as effect,
entity::entity::Entity2D,
layer::layer::{Layer2D, LayerID},
Expand All @@ -14,11 +15,11 @@ use winit::{
};

pub struct EffectSystem {
pub engine: effect::Engine,
engine: effect::Engine,
}

impl EffectSystem {
pub fn new(screen_dimensions: PhysicalSize<u32>) -> (Self, EventLoop<()>) {
pub fn new(screen_dimensions: PhysicalSize<u32>, camera_fov: f32) -> (Self, EventLoop<()>) {
let event_loop = EventLoop::new().unwrap();
event_loop.set_control_flow(ControlFlow::Poll);
let window = WindowBuilder::new()
Expand All @@ -27,7 +28,7 @@ impl EffectSystem {
.with_resizable(false)
.build(&event_loop)
.unwrap();
let engine = pollster::block_on(effect::Engine::new(window));
let engine = pollster::block_on(effect::Engine::new(window, camera_fov));
(Self { engine }, event_loop)
}

Expand Down Expand Up @@ -69,15 +70,22 @@ impl EffectSystem {
self.engine.set_entities(layer, entities);
}

pub fn device(&self) -> &wgpu::Device {
self.engine.device()
pub fn camera(&self) -> &Camera2D {
self.engine.camera()
}

pub fn queue(&self) -> &wgpu::Queue {
self.engine.queue()
pub fn camera_mut(&mut self) -> &mut Camera2D {
self.engine.camera_mut()
}

pub fn update_camera(&mut self) {
self.engine.update_camera();
}
}

pub fn init_engine(screen_dimensions: PhysicalSize<u32>) -> (EffectSystem, EventLoop<()>) {
EffectSystem::new(screen_dimensions)
pub fn init_engine(
screen_dimensions: PhysicalSize<u32>,
camera_fov: f32,
) -> (EffectSystem, EventLoop<()>) {
EffectSystem::new(screen_dimensions, camera_fov)
}
16 changes: 10 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::time::{Duration, Instant};

use effect_engine::engine::{
camera::camera::Camera2DSystem,
entity::entity::{Entity2D, EntitySystem2D},
layer::layer::{Layer2DSystem, LayerID},
primitives::vector::Vector3,
Expand All @@ -13,7 +14,7 @@ use winit::{

fn main() {
println!("Hello, world!");
let (mut app, event_loop) = effect_engine::init_engine(PhysicalSize::new(800, 600));
let (mut app, event_loop) = effect_engine::init_engine(PhysicalSize::new(800, 600), 90.0);
let mut before = Instant::now();
let mut after = Instant::now();
let tex_id = TextureID("tree");
Expand All @@ -27,9 +28,9 @@ fn main() {
let position = Vector3::new(-0.5, -0.5, 0.0);
let ent = app.init_entity(position, evil_id, &mut layer);
let mut ent_good = app.init_entity(position, tex_id, &mut layer);
EntitySystem2D::set_position(&mut ent_good, Vector3::new(0.5, 0.0, 0.0));
EntitySystem2D::set_position(&mut ent_good, Vector3::new(0.0, 0.0, 0.0));
EntitySystem2D::set_rotation(&mut ent_good, 30.0);
EntitySystem2D::set_scale(&mut ent_good, 0.5);
EntitySystem2D::set_scale(&mut ent_good, 0.25);
let mut ents_owner = vec![ent, ent_good];
let mut ents = Vec::new();
for ent in ents_owner.iter() {
Expand All @@ -38,12 +39,15 @@ fn main() {
app.set_entities(&mut layer, ents.as_slice());
drop(ents);
let mut layers = vec![layer];
let camera = app.camera_mut();
Camera2DSystem::transform(camera, Vector3::new(-0.5, -0.5, 0.0));
app.update_camera();

let mut rotation = 0.0;
let _ = event_loop.run(|event, control| {
after = Instant::now();
let delta_time = after - before;
app.engine.input(&event, &delta_time);
// app.engine.input(&event, &delta_time);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
Expand All @@ -52,7 +56,7 @@ fn main() {
control.exit();
}
Event::AboutToWait => {
app.engine.update(&delta_time);
// app.engine.update(&delta_time);
EntitySystem2D::set_rotation(&mut ents_owner.get_mut(1).unwrap(), rotation);
let mut ents = Vec::new();
for ent in ents_owner.iter() {
Expand All @@ -62,7 +66,7 @@ fn main() {
drop(ents);
rotation += 0.05;
rotation = rotation % 360.0;
app.engine.render(&layers).unwrap();
app.render(&layers).unwrap();
}
_ => (),
}
Expand Down
Loading

0 comments on commit bbbb220

Please sign in to comment.