Add helper methods to Transform
This commit is contained in:
parent
265c3dbc5a
commit
836afe2c0e
|
@ -3,6 +3,7 @@ mod render;
|
||||||
mod input_event;
|
mod input_event;
|
||||||
mod resources;
|
mod resources;
|
||||||
mod ecs;
|
mod ecs;
|
||||||
|
mod math;
|
||||||
|
|
||||||
use ecs::components::model_2d::Model2dComponent;
|
use ecs::components::model_2d::Model2dComponent;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
/// Convert degrees to radians
|
||||||
|
pub fn degrees_to_radians(degrees: f32) -> f32 {
|
||||||
|
degrees * PI / 180.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert radians to degrees
|
||||||
|
pub fn radians_to_degrees(radians: f32) -> f32 {
|
||||||
|
radians * 180.0 / PI
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Angle {
|
||||||
|
Degrees(f32),
|
||||||
|
Radians(f32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Angle {
|
||||||
|
/// Converts Angle to radians.
|
||||||
|
/// (conversion is only done if the Angle is in degrees).
|
||||||
|
pub fn to_radians(&self) -> f32 {
|
||||||
|
match *self {
|
||||||
|
Self::Degrees(d) => degrees_to_radians(d),
|
||||||
|
Self::Radians(r) => r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts Angle to degrees.
|
||||||
|
/// (conversion is only done if the Angle is in radians).
|
||||||
|
pub fn to_degrees(&self) -> f32 {
|
||||||
|
match *self {
|
||||||
|
Self::Degrees(d) => d,
|
||||||
|
Self::Radians(r) => radians_to_degrees(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
/// Re-export of glam library
|
||||||
|
pub use glam::*;
|
||||||
|
|
||||||
|
pub mod angle;
|
||||||
|
pub use angle::*;
|
|
@ -1,19 +1,24 @@
|
||||||
use hecs::Entity;
|
use hecs::Entity;
|
||||||
|
|
||||||
use super::{mesh::Mesh, material::Material};
|
use super::{mesh::Mesh, material::Material, transform::Transform};
|
||||||
|
|
||||||
pub struct RenderJob {
|
pub struct RenderJob {
|
||||||
mesh: Mesh,
|
mesh: Mesh,
|
||||||
material: Material,
|
material: Material,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
|
|
||||||
|
pub transform: Option<Transform>,
|
||||||
|
pub last_transform: Option<Transform>, // TODO: render interpolation
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderJob {
|
impl RenderJob {
|
||||||
pub fn new(mesh: Mesh, material: Material, entity: Entity) -> Self {
|
pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Option<Transform>, last_transform: Option<Transform>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mesh,
|
mesh,
|
||||||
material,
|
material,
|
||||||
entity,
|
entity,
|
||||||
|
transform,
|
||||||
|
last_transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::borrow::Cow;
|
||||||
use async_std::sync::Mutex;
|
use async_std::sync::Mutex;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use tracing::debug;
|
||||||
use wgpu::{BindGroup, BindGroupLayout};
|
use wgpu::{BindGroup, BindGroupLayout};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
@ -55,7 +56,6 @@ pub struct BasicRenderer {
|
||||||
|
|
||||||
buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
|
buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
|
||||||
|
|
||||||
transform_uniform: Transform,
|
|
||||||
transform_bind_group: wgpu::BindGroup,
|
transform_bind_group: wgpu::BindGroup,
|
||||||
transform_buffer: wgpu::Buffer,
|
transform_buffer: wgpu::Buffer,
|
||||||
}
|
}
|
||||||
|
@ -115,10 +115,6 @@ impl BasicRenderer {
|
||||||
};
|
};
|
||||||
surface.configure(&device, &config);
|
surface.configure(&device, &config);
|
||||||
|
|
||||||
|
|
||||||
/* let diffuse_bytes = include_bytes!("../../res/happy-tree.png");
|
|
||||||
let diffuse_texture = RenderTexture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap(); */
|
|
||||||
|
|
||||||
let texture_bind_group_layout =
|
let texture_bind_group_layout =
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
entries: &[
|
entries: &[
|
||||||
|
@ -144,52 +140,16 @@ impl BasicRenderer {
|
||||||
label: Some("texture_bind_group_layout"),
|
label: Some("texture_bind_group_layout"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let transform_bind_group_layout =
|
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("texture_bind_group_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
/* let diffuse_bind_group = device.create_bind_group(
|
|
||||||
&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &texture_bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: wgpu::BindingResource::TextureView(diffuse_texture.view()),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: wgpu::BindingResource::Sampler(diffuse_texture.sampler()),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
label: Some("diffuse_bind_group"),
|
|
||||||
}
|
|
||||||
); */
|
|
||||||
|
|
||||||
|
|
||||||
let shader_src = resources::load_string("shader/base_2d.wgsl").await.expect("Failed to load shader!");
|
let shader_src = resources::load_string("shader/base_2d.wgsl").await.expect("Failed to load shader!");
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("Shader"),
|
label: Some("Shader"),
|
||||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&shader_src)),
|
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&shader_src)),
|
||||||
});
|
});
|
||||||
|
|
||||||
let transform_uniform = Transform::new();
|
|
||||||
let transform_buffer = device.create_buffer_init(
|
let transform_buffer = device.create_buffer_init(
|
||||||
&wgpu::util::BufferInitDescriptor {
|
&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Camera Buffer"),
|
label: Some("Transform Buffer"),
|
||||||
contents: bytemuck::cast_slice(&[transform_uniform]),
|
contents: bytemuck::cast_slice(&[Transform::new()]),
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -220,8 +180,6 @@ impl BasicRenderer {
|
||||||
],
|
],
|
||||||
label: Some("transform_bind_group"),
|
label: Some("transform_bind_group"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let mut pipelines = HashMap::new();
|
let mut pipelines = HashMap::new();
|
||||||
pipelines.insert(0, Arc::new(FullRenderPipeline::new(&device, &config, &shader,
|
pipelines.insert(0, Arc::new(FullRenderPipeline::new(&device, &config, &shader,
|
||||||
|
@ -244,7 +202,6 @@ impl BasicRenderer {
|
||||||
render_jobs: HashMap::new(),
|
render_jobs: HashMap::new(),
|
||||||
buffer_storage: HashMap::new(),
|
buffer_storage: HashMap::new(),
|
||||||
|
|
||||||
transform_uniform,
|
|
||||||
transform_buffer,
|
transform_buffer,
|
||||||
transform_bind_group,
|
transform_bind_group,
|
||||||
}
|
}
|
||||||
|
@ -339,7 +296,14 @@ impl BasicRenderer {
|
||||||
impl Renderer for BasicRenderer {
|
impl Renderer for BasicRenderer {
|
||||||
async fn prepare(&mut self, main_world: &World) {
|
async fn prepare(&mut self, main_world: &World) {
|
||||||
for (entity, (model, transform)) in main_world.query::<(&Model2dComponent, Option<&TransformComponent>)>().iter() {
|
for (entity, (model, transform)) in main_world.query::<(&Model2dComponent, Option<&TransformComponent>)>().iter() {
|
||||||
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity);
|
let transform = match transform {
|
||||||
|
Some(transform) => {
|
||||||
|
Some(transform.transform)
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform, None);
|
||||||
|
|
||||||
// Insert the new job into the queue
|
// Insert the new job into the queue
|
||||||
if let Some(shader_jobs) = self.render_jobs.get_mut(&model.material.shader_id) {
|
if let Some(shader_jobs) = self.render_jobs.get_mut(&model.material.shader_id) {
|
||||||
|
@ -352,15 +316,7 @@ impl Renderer for BasicRenderer {
|
||||||
let buffers = self.create_model_buffers(model);
|
let buffers = self.create_model_buffers(model);
|
||||||
self.buffer_storage.insert(entity, buffers);
|
self.buffer_storage.insert(entity, buffers);
|
||||||
} else {
|
} else {
|
||||||
let mesh = &model.mesh;
|
|
||||||
|
|
||||||
// update existing buffers
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(transform) = transform {
|
|
||||||
self.transform_uniform = transform.transform;
|
|
||||||
|
|
||||||
self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[self.transform_uniform]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,13 +356,19 @@ impl Renderer for BasicRenderer {
|
||||||
if let Some(jobs) = pipeline_jobs {
|
if let Some(jobs) = pipeline_jobs {
|
||||||
for job in jobs.iter() {
|
for job in jobs.iter() {
|
||||||
let mesh = job.mesh();
|
let mesh = job.mesh();
|
||||||
let buffers = self.buffer_storage.get(&job.entity()).unwrap(); // TODO: create buffers if not made
|
let buffers = self.buffer_storage.get(&job.entity()).unwrap();
|
||||||
|
|
||||||
if let Some(tex) = buffers.texture_bindgroup.as_ref() {
|
if let Some(tex) = buffers.texture_bindgroup.as_ref() {
|
||||||
render_pass.set_bind_group(0, &tex, &[]);
|
render_pass.set_bind_group(0, &tex, &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_pass.set_bind_group(1, &self.transform_bind_group, &[]);
|
// If the job has a transform, set the uniform to it
|
||||||
|
if let Some(transform) = job.transform {
|
||||||
|
self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[transform]));
|
||||||
|
render_pass.set_bind_group(1, &self.transform_bind_group, &[]);
|
||||||
|
} else {
|
||||||
|
debug!("//TODO: clear transform uniform if the RenderJob doesn't have a transform.");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(indices) = buffers.buffer_indices.as_ref() {
|
if let Some(indices) = buffers.buffer_indices.as_ref() {
|
||||||
let indices_len = indices.count().unwrap(); // index buffers will have count, if not thats a bug
|
let indices_len = indices.count().unwrap(); // index buffers will have count, if not thats a bug
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use glam::Vec3;
|
use glam::{Vec3, Mat4, Quat};
|
||||||
|
|
||||||
|
use crate::math::angle::{self, Angle};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
@ -14,33 +16,115 @@ impl Default for Transform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl Transform {
|
impl Transform {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_glam(matrix: glam::Mat4) -> Self {
|
pub fn from_matrix(matrix: glam::Mat4) -> Self {
|
||||||
Self {
|
Self {
|
||||||
matrix,
|
matrix,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create Transform from scale, rotation (in degrees), and translation
|
||||||
|
pub fn from_scale_rotation_deg_translation(scale: Vec3, mut rotation: Vec3, translation: Vec3) -> Self {
|
||||||
|
rotation.x = angle::degrees_to_radians(rotation.x);
|
||||||
|
rotation.y = angle::degrees_to_radians(rotation.y);
|
||||||
|
rotation.z = angle::degrees_to_radians(rotation.z);
|
||||||
|
let rotation_quat = glam::Quat::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
|
||||||
|
|
||||||
|
let matrix = glam::Mat4::from_scale_rotation_translation(scale, rotation_quat, translation);
|
||||||
|
|
||||||
|
Self::from_matrix(matrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create Transform from scale, rotation (in radians), and translation
|
||||||
|
pub fn from_scale_rotation_rad_translation(scale: Vec3, rotation: Vec3, translation: Vec3) -> Self {
|
||||||
|
let rotation_quat = glam::Quat::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
|
||||||
|
let matrix = glam::Mat4::from_scale_rotation_translation(scale, rotation_quat, translation);
|
||||||
|
|
||||||
|
Self::from_matrix(matrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create Transform from scale, rotation (as a quaternion), and translation
|
||||||
|
pub fn from_scale_rotation_quat_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
|
||||||
|
let matrix = glam::Mat4::from_scale_rotation_translation(scale, rotation, translation);
|
||||||
|
|
||||||
|
Self::from_matrix(matrix)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn translate_vec3(&mut self, vec: Vec3) -> &mut Self {
|
pub fn translate_vec3(&mut self, vec: Vec3) -> &mut Self {
|
||||||
/* let first_col = self.matrix.col(0);
|
|
||||||
let second_col = self.matrix.col(1);
|
|
||||||
let third_col = self.matrix.col(2);
|
|
||||||
|
|
||||||
//let fourth_col = self.matrix.col_mut(3);
|
|
||||||
let w_axis = &mut self.matrix.w_axis;
|
|
||||||
//first_col.w
|
|
||||||
//fourth_col = fourth_col.x * vec.x + second_col * vec.y + third_col * vec.z + fourth_col.clone();
|
|
||||||
w_axis.x += vec.x;
|
|
||||||
w_axis.y += vec.y;
|
|
||||||
w_axis.z += vec.z; */
|
|
||||||
|
|
||||||
let translation = glam::Mat4::from_translation(vec);
|
let translation = glam::Mat4::from_translation(vec);
|
||||||
self.matrix *= translation;
|
self.matrix *= translation;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rotate around the given axis.
|
||||||
|
pub fn rotate_axis(&mut self, axis: Vec3, angle: Angle) -> &mut Self {
|
||||||
|
let radians = angle.to_radians();
|
||||||
|
|
||||||
|
let rotation = glam::Mat4::from_axis_angle(axis, radians);
|
||||||
|
self.matrix *= rotation;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the transform with degrees
|
||||||
|
pub fn rotate_degrees(&mut self, mut x: f32, mut y: f32, mut z: f32) -> &mut Self {
|
||||||
|
// Convert degrees to radians
|
||||||
|
x = angle::degrees_to_radians(x);
|
||||||
|
y = angle::degrees_to_radians(y);
|
||||||
|
z = angle::degrees_to_radians(z);
|
||||||
|
|
||||||
|
let rotation = glam::Mat4::from_euler(glam::EulerRot::XYZ, x, y, z);
|
||||||
|
self.matrix *= rotation;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the transform with degrees in a vec
|
||||||
|
pub fn rotate_degrees_vec(&mut self, mut rotation: Vec3) -> &mut Self {
|
||||||
|
self.rotate_degrees(rotation.x, rotation.y, rotation.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the transform with radians
|
||||||
|
pub fn rotate_radians(&mut self, rotation: Vec3) -> &mut Self {
|
||||||
|
let rotation = glam::Mat4::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z);
|
||||||
|
self.matrix *= rotation;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rotate the transform with a quaternion
|
||||||
|
pub fn rotate_quat(&mut self, quat: glam::Quat) -> &mut Self {
|
||||||
|
let rotation = glam::Mat4::from_quat(quat);
|
||||||
|
self.matrix *= rotation;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rotate around the x axis.
|
||||||
|
pub fn rotate_x(&mut self, angle: Angle) -> &mut Self {
|
||||||
|
self.rotate_axis(Vec3::new(1.0, 0.0, 0.0), angle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rotate around the y axis.
|
||||||
|
pub fn rotate_y(&mut self, angle: Angle) -> &mut Self {
|
||||||
|
self.rotate_axis(Vec3::new(0.0, 1.0, 0.0), angle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rotate around the z axis.
|
||||||
|
pub fn rotate_z(&mut self, angle: Angle) -> &mut Self {
|
||||||
|
self.rotate_axis(Vec3::new(0.0, 0.0, 0.0), angle)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(&mut self, scale: Vec3) -> &mut Self {
|
||||||
|
let scale = Mat4::from_scale(scale);
|
||||||
|
self.matrix *= scale;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue