Significant render refactoring, implement transformation matrix
This commit is contained in:
parent
22865bbc33
commit
432c54004e
|
@ -95,15 +95,6 @@ version = "1.0.69"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
|
@ -427,16 +418,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "cgmath"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
|
@ -727,6 +708,15 @@ version = "0.27.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
|
||||
|
||||
[[package]]
|
||||
name = "glam"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad83ab008a4fa3b31dfa713dd41b5a9bdea1e94e4cf1e2fc274ffbd49b0271d3"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.6"
|
||||
|
@ -791,7 +781,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-descriptor-types",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -812,6 +802,15 @@ dependencies = [
|
|||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hassle-rs"
|
||||
version = "0.9.0"
|
||||
|
@ -827,6 +826,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hecs"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d2711ad60b74f2f3d0c0ac338a58410a5249da44005971ae806d2925e6b5167"
|
||||
dependencies = [
|
||||
"hashbrown 0.13.2",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
|
@ -874,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -990,7 +999,8 @@ dependencies = [
|
|||
"async-trait",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"cgmath",
|
||||
"glam",
|
||||
"hecs",
|
||||
"image",
|
||||
"instant",
|
||||
"specs",
|
||||
|
@ -1569,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "102269e720bb814df57e136161cad841f2b6f411e003ac748fc48aaf2363bea3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"mopa",
|
||||
"rayon",
|
||||
"shred-derive",
|
||||
|
@ -1673,7 +1683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4ea85dac2880f84d4025ff5ace80cda6d8bc43bc88b6a389b9277fcf894b51e9"
|
||||
dependencies = [
|
||||
"crossbeam-queue",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"hibitset",
|
||||
"log",
|
||||
"rayon",
|
||||
|
@ -1694,6 +1704,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spirv"
|
||||
version = "0.2.0+1.5.4"
|
||||
|
|
|
@ -17,10 +17,12 @@ cfg-if = "1"
|
|||
bytemuck = { version = "1.12", features = [ "derive" ] }
|
||||
image = { version = "0.24", default-features = false, features = ["png", "jpeg"] }
|
||||
anyhow = "1.0"
|
||||
cgmath = "0.18"
|
||||
#cgmath = "0.18"
|
||||
tobj = { version = "3.2.1", features = [
|
||||
"async",
|
||||
]}
|
||||
instant = "0.1"
|
||||
async-trait = "0.1.65"
|
||||
specs = { version = "0.18.0", features = [ "derive" ] }
|
||||
hecs = "0.10.3"
|
||||
glam = { version = "0.24.0", features = ["bytemuck"] }
|
||||
|
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -10,13 +10,16 @@ struct VertexOutput {
|
|||
@location(0) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> u_model_transform: mat4x4<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
model: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.tex_coords = model.tex_coords;
|
||||
out.clip_position = vec4<f32>(model.position, 1.0);
|
||||
out.clip_position = u_model_transform * vec4<f32>(model.position, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
pub mod model_2d;
|
||||
pub mod transform;
|
|
@ -1,4 +1,18 @@
|
|||
#[derive(Component, Debug, Default)]
|
||||
pub struct Model2d {
|
||||
pub vertices: Vec<Vertex>,
|
||||
use specs::{Component, DenseVecStorage};
|
||||
|
||||
use crate::render::{vertex::Vertex, mesh::Mesh, material::Material};
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
pub struct Model2dComponent {
|
||||
pub mesh: Mesh,
|
||||
pub material: Material,
|
||||
}
|
||||
|
||||
impl Model2dComponent {
|
||||
pub fn new(mesh: Mesh, material: Material) -> Self {
|
||||
Self {
|
||||
mesh,
|
||||
material
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
use specs::{Component, DenseVecStorage};
|
||||
|
||||
use crate::render::transform::Transform;
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
pub struct TransformComponent {
|
||||
pub transform: Transform,
|
||||
}
|
||||
|
||||
impl Default for TransformComponent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
transform: Transform::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransformComponent {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn from_transform(transform: Transform) -> Self {
|
||||
Self {
|
||||
transform
|
||||
}
|
||||
}
|
||||
}
|
78
src/game.rs
78
src/game.rs
|
@ -1,9 +1,8 @@
|
|||
use std::{sync::Arc};
|
||||
use std::{sync::Arc, cell::RefCell};
|
||||
|
||||
use async_std::{task::block_on, sync::Mutex};
|
||||
|
||||
use specs::{Dispatcher, World};
|
||||
|
||||
use hecs::World;
|
||||
use tracing::{metadata::LevelFilter, info, debug, warn};
|
||||
use tracing_subscriber::{
|
||||
layer::{Layer, SubscriberExt},
|
||||
|
@ -13,24 +12,22 @@ use tracing_subscriber::{
|
|||
|
||||
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}, event_loop::{EventLoop, ControlFlow}};
|
||||
|
||||
use crate::{render::renderer::{Renderer, BasicRenderer}, input_event::InputEvent};
|
||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::components::{model_2d::Model2dComponent, transform::TransformComponent}};
|
||||
|
||||
struct GameLoop<'a, 'b> {
|
||||
struct GameLoop {
|
||||
window: Arc<Window>,
|
||||
renderer: Box<dyn Renderer>,
|
||||
|
||||
world: Arc<Mutex<World>>,
|
||||
system_dispatchers: Vec<Dispatcher<'a, 'b>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> GameLoop<'a, 'b> {
|
||||
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, system_dispatchers: Vec<Dispatcher<'a, 'b>>) -> GameLoop<'a, 'b> {
|
||||
impl GameLoop {
|
||||
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>) -> GameLoop {
|
||||
Self {
|
||||
window: Arc::clone(&window),
|
||||
renderer: Box::new(BasicRenderer::create_with_window(window).await),
|
||||
|
||||
world,
|
||||
system_dispatchers,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,10 +40,10 @@ impl<'a, 'b> GameLoop<'a, 'b> {
|
|||
}
|
||||
|
||||
async fn update(&mut self) {
|
||||
let world = self.world.lock().await;
|
||||
/* let world = self.world.lock().await;
|
||||
for dispatcher in self.system_dispatchers.iter_mut() {
|
||||
dispatcher.dispatch(&world);
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
|
||||
|
@ -120,8 +117,41 @@ impl<'a, 'b> GameLoop<'a, 'b> {
|
|||
},
|
||||
|
||||
Event::RedrawRequested(window_id) if window_id == self.window.id() => {
|
||||
// Update the world
|
||||
self.update().await;
|
||||
|
||||
|
||||
// Collect models from the ecs world
|
||||
/* let mut jobs = vec![];
|
||||
let world = self.world.lock().await;
|
||||
let model2d_storage = world.read_storage::<Model2d>();
|
||||
|
||||
for model in model2d_storage.join() {
|
||||
let job = RenderJob::new(&model.mesh);
|
||||
jobs.push(job);
|
||||
}
|
||||
|
||||
// drop some stuff for the borrow checker
|
||||
drop(model2d_storage);
|
||||
drop(world);
|
||||
|
||||
for job in jobs.iter() {
|
||||
println!("job");
|
||||
} */
|
||||
|
||||
let mut world = self.world.lock().await;
|
||||
|
||||
for (ent, (transform,)) in world.query_mut::<(&mut TransformComponent,)>() {
|
||||
transform.transform.translate_vec3(glam::Vec3::new(0.0, 0.001, 0.0));
|
||||
}
|
||||
|
||||
for (ent, (transform,)) in world.query::<(&TransformComponent,)>().iter() {
|
||||
println!("transform pos: {:?}", transform.transform);
|
||||
}
|
||||
|
||||
self.renderer.as_mut().prepare(&world).await;
|
||||
drop(world);
|
||||
|
||||
match self.renderer.as_mut().render().await {
|
||||
Ok(_) => {}
|
||||
// Reconfigure the surface if lost
|
||||
|
@ -141,22 +171,20 @@ impl<'a, 'b> GameLoop<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Game<'a, 'b> {
|
||||
pub struct Game {
|
||||
world: Option<Arc<Mutex<World>>>,
|
||||
system_dispatchers: Option<Vec<Dispatcher<'a, 'b>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Default for Game<'a, 'b> {
|
||||
impl Default for Game {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
world: None,
|
||||
system_dispatchers: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Game<'static, 'static> {
|
||||
pub async fn initialize() -> Game<'static, 'static> {
|
||||
impl Game {
|
||||
pub async fn initialize() -> Game {
|
||||
let filter = FilterFn::new(|metadata| {
|
||||
metadata.module_path()
|
||||
.unwrap_or_else(|| metadata.target())
|
||||
|
@ -184,27 +212,13 @@ impl<'a, 'b> Game<'static, 'static> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_dispatchers(&mut self, dispatchers: Vec<Dispatcher<'static, 'static>>) -> &mut Self {
|
||||
self.system_dispatchers = Some(dispatchers);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_dispatcher(&mut self, dispatcher: Dispatcher<'static, 'static>) -> &mut Self {
|
||||
self.system_dispatchers.get_or_insert_with(|| Vec::new()).push(dispatcher);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
let world = self.world.take().expect("ECS World was never given to Game!");
|
||||
let system_dispatchers = self.system_dispatchers
|
||||
.take().unwrap_or_else(|| Vec::new());
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||
|
||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatchers).await;
|
||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world).await;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
g_loop.run_sync(event, control_flow);
|
||||
|
|
62
src/main.rs
62
src/main.rs
|
@ -1,13 +1,20 @@
|
|||
mod system;
|
||||
mod game;
|
||||
mod render;
|
||||
mod input_event;
|
||||
mod resources;
|
||||
mod ecs;
|
||||
|
||||
use ecs::components::model_2d::Model2dComponent;
|
||||
|
||||
use ecs::components::transform::TransformComponent;
|
||||
use game::Game;
|
||||
use specs::*;
|
||||
use hecs::World;
|
||||
|
||||
#[derive(Component, Debug, Default)]
|
||||
use crate::render::material::Material;
|
||||
use crate::render::texture::Texture;
|
||||
//use specs::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Point2d {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
@ -28,7 +35,7 @@ impl Point2d {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Default)]
|
||||
#[derive(Debug, Default)]
|
||||
struct Point3d {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
@ -51,29 +58,34 @@ impl Point3d {
|
|||
}
|
||||
}
|
||||
|
||||
struct TestingSystem;
|
||||
|
||||
impl<'a> System<'a> for TestingSystem {
|
||||
// These are the resources required for execution.
|
||||
// You can also define a struct and `#[derive(SystemData)]`,
|
||||
// see the `full` example.
|
||||
type SystemData = (ReadStorage<'a, Point2d>,);
|
||||
|
||||
fn run(&mut self, (point,): Self::SystemData) {
|
||||
// The `.join()` combines multiple component storages,
|
||||
// so we get access to all entities which have
|
||||
// both a position and a velocity.
|
||||
for (point,) in (&point,).join() {
|
||||
//point.0 += vel.0;
|
||||
println!("Entity at: {}", point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let mut world = World::new();
|
||||
world.register::<Point2d>();
|
||||
|
||||
world.spawn((Point2d::new(10, 10), Point3d::new(50, 50, 50)));
|
||||
|
||||
let diffuse_bytes = include_bytes!("../res/happy-tree.png");
|
||||
let diffuse_texture = Texture::from_bytes(diffuse_bytes).unwrap();
|
||||
world.spawn((Model2dComponent::new(
|
||||
render::mesh::Mesh {
|
||||
vertices: crate::render::vertex::VERTICES.to_vec(),
|
||||
indices: Some(crate::render::vertex::INDICES.to_vec())
|
||||
}, Material {
|
||||
shader_id: 0,
|
||||
texture: diffuse_texture
|
||||
}),
|
||||
TransformComponent::new(),
|
||||
));
|
||||
|
||||
for (id, (point2d,)) in world.query::<(&Point2d,)>().iter() {
|
||||
println!("Entity {} is at 2d position: {:?}", id.id(), point2d);
|
||||
}
|
||||
|
||||
Game::initialize().await
|
||||
.with_world(world)
|
||||
.run().await;
|
||||
|
||||
/* world.register::<Point2d>();
|
||||
world.register::<Point3d>();
|
||||
|
||||
world.create_entity()
|
||||
|
@ -89,7 +101,7 @@ async fn main() {
|
|||
Game::initialize().await
|
||||
.with_world(world)
|
||||
.with_dispatcher(dispatcher)
|
||||
.run().await;
|
||||
.run().await; */
|
||||
|
||||
/* let mut game = Game::initialize().await;
|
||||
game.run().await; */
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
use super::texture::Texture;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Material {
|
||||
pub shader_id: u32,
|
||||
pub texture: Texture,
|
||||
}
|
|
@ -2,28 +2,23 @@ use wgpu::{BindGroup, BindGroupLayout};
|
|||
|
||||
use super::{vertex::Vertex, render_buffer::{BufferStorage}};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Mesh {
|
||||
//material
|
||||
//texture: Option<Texture>,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Option<Vec<u16>>,
|
||||
|
||||
pub buffer_vertex: BufferStorage,
|
||||
/* pub buffer_vertex: BufferStorage,
|
||||
pub buffer_indices: Option<BufferStorage>, // TOOD: make optional
|
||||
|
||||
pub texture_bindgroup: Option<BindGroup>,
|
||||
pub texture_layout: Option<BindGroupLayout>
|
||||
pub texture_layout: Option<BindGroupLayout> */
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn new(vertices: Vec<Vertex>, indices: Option<Vec<u16>>, buffer_vertex: BufferStorage, buffer_indices: Option<BufferStorage>, texture_bindgroup: Option<BindGroup>, texture_layout: Option<BindGroupLayout>) -> Self {
|
||||
pub fn new(vertices: Vec<Vertex>, indices: Option<Vec<u16>>) -> Self {
|
||||
Self {
|
||||
vertices,
|
||||
indices,
|
||||
buffer_vertex,
|
||||
buffer_indices,
|
||||
texture_bindgroup,
|
||||
texture_layout,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,3 +6,6 @@ pub mod render_buffer;
|
|||
pub mod render_job;
|
||||
pub mod mesh;
|
||||
pub mod texture;
|
||||
pub mod shader_loader;
|
||||
pub mod material;
|
||||
pub mod transform;
|
|
@ -1,17 +1,31 @@
|
|||
use super::{mesh::Mesh};
|
||||
use hecs::Entity;
|
||||
|
||||
use super::{mesh::Mesh, material::Material};
|
||||
|
||||
pub struct RenderJob {
|
||||
mesh: Mesh
|
||||
mesh: Mesh,
|
||||
material: Material,
|
||||
entity: Entity,
|
||||
}
|
||||
|
||||
impl RenderJob {
|
||||
pub fn new(mesh: Mesh) -> Self {
|
||||
pub fn new(mesh: Mesh, material: Material, entity: Entity) -> Self {
|
||||
Self {
|
||||
mesh,
|
||||
material,
|
||||
entity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mesh(&self)-> &Mesh {
|
||||
&self.mesh
|
||||
}
|
||||
|
||||
pub fn material(&self)-> &Material {
|
||||
&self.material
|
||||
}
|
||||
|
||||
pub fn entity(&self)-> Entity {
|
||||
self.entity
|
||||
}
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
use std::ops::Range;
|
||||
use std::{ops::Range, cell::Ref};
|
||||
|
||||
use wgpu::{PipelineLayout, RenderPipeline, RenderPass};
|
||||
use wgpu::{PipelineLayout, RenderPipeline, RenderPass, VertexBufferLayout, BindGroupLayout};
|
||||
|
||||
use super::{render_job::RenderJob, vertex::Vertex, desc_buf_lay::DescVertexBufferLayout};
|
||||
|
||||
pub struct FullRenderPipeline {
|
||||
layout: PipelineLayout,
|
||||
wgpu_pipeline: RenderPipeline,
|
||||
jobs: Vec<RenderJob>,
|
||||
}
|
||||
|
||||
impl FullRenderPipeline {
|
||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, jobs: Vec<RenderJob>) -> Self {
|
||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, buffer_layouts: Vec<VertexBufferLayout>, bind_group_layouts: Vec<&BindGroupLayout>) -> FullRenderPipeline {
|
||||
// Extract the layouts from all the jobs
|
||||
let mut buffer_layouts = vec![];
|
||||
/* let mut buffer_layouts = vec![];
|
||||
let mut bind_group_layouts = vec![];
|
||||
for job in jobs.iter() {
|
||||
// Push layout for the vertex buffer, index buffer doesn't need one
|
||||
|
@ -22,7 +21,7 @@ impl FullRenderPipeline {
|
|||
if let Some(layout) = job.mesh().texture_layout.as_ref() {
|
||||
bind_group_layouts.push(layout);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
|
@ -72,7 +71,6 @@ impl FullRenderPipeline {
|
|||
Self {
|
||||
layout: render_pipeline_layout,
|
||||
wgpu_pipeline: render_pipeline,
|
||||
jobs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,10 +84,11 @@ impl FullRenderPipeline {
|
|||
&self.wgpu_pipeline
|
||||
}
|
||||
|
||||
pub fn render<'a>(&'a self, pass: &mut RenderPass<'a>, vertices: Range<u32>, instances: Range<u32>) {
|
||||
pass.set_pipeline(&self.wgpu_pipeline);
|
||||
pub fn render<'a>(&'a self, jobs: &'a Vec<RenderJob>, pass: &'a mut RenderPass<'a>, vertices: Range<u32>, instances: Range<u32>) {
|
||||
todo!()
|
||||
/* pass.set_pipeline(&self.wgpu_pipeline);
|
||||
|
||||
for job in self.jobs.iter() {
|
||||
for job in jobs.iter() {
|
||||
let mesh = job.mesh();
|
||||
|
||||
if let Some(tex) = mesh.texture_bindgroup.as_ref() {
|
||||
|
@ -106,6 +105,6 @@ impl FullRenderPipeline {
|
|||
pass.set_vertex_buffer(mesh.buffer_vertex.slot(), mesh.buffer_vertex.buffer().slice(..));
|
||||
pass.draw(vertices.clone(), instances.clone());
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
|
@ -1,23 +1,43 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use async_std::sync::Mutex;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use wgpu::{BindGroup, BindGroupLayout};
|
||||
use wgpu::util::DeviceExt;
|
||||
use winit::window::Window;
|
||||
|
||||
use hecs::{World, Entity};
|
||||
|
||||
use crate::ecs::components::model_2d::Model2dComponent;
|
||||
use crate::ecs::components::transform::TransformComponent;
|
||||
use crate::resources;
|
||||
|
||||
use super::texture::Texture;
|
||||
use super::desc_buf_lay::DescVertexBufferLayout;
|
||||
use super::texture::RenderTexture;
|
||||
use super::transform::Transform;
|
||||
use super::{render_pipeline::FullRenderPipeline, vertex::{VERTICES}, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Renderer {
|
||||
async fn prepare(&mut self, main_world: &World);
|
||||
async fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
|
||||
|
||||
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>;
|
||||
fn add_render_pipeline(&mut self, pipeline: FullRenderPipeline);
|
||||
fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>);
|
||||
}
|
||||
|
||||
struct RenderBufferStorage {
|
||||
buffer_vertex: BufferStorage,
|
||||
buffer_indices: Option<BufferStorage>,
|
||||
|
||||
render_texture: Option<RenderTexture>,
|
||||
texture_bindgroup: Option<BindGroup>,
|
||||
texture_layout: Option<BindGroupLayout>
|
||||
}
|
||||
|
||||
pub struct BasicRenderer {
|
||||
|
@ -30,7 +50,14 @@ pub struct BasicRenderer {
|
|||
|
||||
pub clear_color: wgpu::Color,
|
||||
|
||||
pub render_pipelines: Vec<FullRenderPipeline>,
|
||||
pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>,
|
||||
pub render_jobs: HashMap<u32, Vec<RenderJob>>,
|
||||
|
||||
buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
|
||||
|
||||
transform_uniform: Transform,
|
||||
transform_bind_group: wgpu::BindGroup,
|
||||
transform_buffer: wgpu::Buffer,
|
||||
}
|
||||
|
||||
impl BasicRenderer {
|
||||
|
@ -89,8 +116,8 @@ impl BasicRenderer {
|
|||
surface.configure(&device, &config);
|
||||
|
||||
|
||||
let diffuse_bytes = include_bytes!("../../res/happy-tree.png");
|
||||
let diffuse_texture = Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
|
||||
/* 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 =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
|
@ -117,7 +144,171 @@ impl BasicRenderer {
|
|||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let diffuse_bind_group = device.create_bind_group(
|
||||
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 = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Shader"),
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&shader_src)),
|
||||
});
|
||||
|
||||
let transform_uniform = Transform::new();
|
||||
let transform_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Camera Buffer"),
|
||||
contents: bytemuck::cast_slice(&[transform_uniform]),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
}
|
||||
);
|
||||
|
||||
let transform_bind_group_layout = 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("transform_bind_group_layout"),
|
||||
});
|
||||
|
||||
let transform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &transform_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: transform_buffer.as_entire_binding(),
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group"),
|
||||
});
|
||||
|
||||
|
||||
|
||||
let mut pipelines = HashMap::new();
|
||||
pipelines.insert(0, Arc::new(FullRenderPipeline::new(&device, &config, &shader,
|
||||
vec![super::vertex::Vertex::desc(),], vec![&texture_bind_group_layout, &transform_bind_group_layout])));
|
||||
|
||||
Self {
|
||||
window,
|
||||
surface,
|
||||
device,
|
||||
queue,
|
||||
config,
|
||||
size,
|
||||
clear_color: wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
},
|
||||
render_pipelines: pipelines,
|
||||
render_jobs: HashMap::new(),
|
||||
buffer_storage: HashMap::new(),
|
||||
|
||||
transform_uniform,
|
||||
transform_buffer,
|
||||
transform_bind_group,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_model_buffers(&mut self, model_2d: &Model2dComponent) -> RenderBufferStorage {
|
||||
let mesh = &model_2d.mesh;
|
||||
|
||||
let vertex_buffer = self.device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(mesh.vertices.as_slice()),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
}
|
||||
);
|
||||
|
||||
let buffer_indices = match mesh.indices.as_ref() {
|
||||
Some(indices) => {
|
||||
let index_buffer = self.device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(&indices),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
}
|
||||
);
|
||||
|
||||
let buffer_indices = BufferStorage::new(index_buffer, 0, Some(indices.len() as u32));
|
||||
|
||||
Some(buffer_indices)
|
||||
},
|
||||
None => {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let texture_img = &model_2d.material.texture;
|
||||
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, &texture_img.img, 0, Some("happy-tree.png")).unwrap();
|
||||
|
||||
let texture_bind_group_layout =
|
||||
self.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,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
// This should match the filterable field of the
|
||||
// corresponding Texture entry above.
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let diffuse_bind_group = self.device.create_bind_group(
|
||||
&wgpu::BindGroupDescriptor {
|
||||
layout: &texture_bind_group_layout,
|
||||
entries: &[
|
||||
|
@ -134,63 +325,53 @@ impl BasicRenderer {
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
let shader_src = resources::load_string("shader.wgsl").await.expect("Failed to load shader!");
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Shader"),
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&shader_src)),
|
||||
});
|
||||
|
||||
let vertex_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(super::vertex::VERTICES),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
}
|
||||
);
|
||||
|
||||
let index_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(super::vertex::INDICES),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
}
|
||||
);
|
||||
|
||||
let job = RenderJob::new(Mesh::new(
|
||||
super::vertex::VERTICES.to_vec(), Some(super::vertex::INDICES.to_vec()),
|
||||
BufferStorage::new(vertex_buffer, 0, None),
|
||||
Some(BufferStorage::new(index_buffer, 0, Some(super::vertex::INDICES.len() as u32))),
|
||||
Some(diffuse_bind_group), Some(texture_bind_group_layout)
|
||||
));
|
||||
|
||||
let pipelines = vec![
|
||||
FullRenderPipeline::new(&device, &config, &shader,
|
||||
vec![job,])
|
||||
];
|
||||
|
||||
Self {
|
||||
window,
|
||||
surface,
|
||||
device,
|
||||
queue,
|
||||
config,
|
||||
size,
|
||||
clear_color: wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
},
|
||||
render_pipelines: pipelines,
|
||||
RenderBufferStorage {
|
||||
buffer_vertex: BufferStorage::new(vertex_buffer, 0, None),
|
||||
buffer_indices,
|
||||
render_texture: None,
|
||||
texture_layout: None,
|
||||
texture_bindgroup: Some(diffuse_bind_group),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Renderer for BasicRenderer {
|
||||
async fn prepare(&mut self, main_world: &World) {
|
||||
for (entity, (model, transform)) in main_world.query::<(&Model2dComponent, Option<&TransformComponent>)>().iter() {
|
||||
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity);
|
||||
|
||||
// Insert the new job into the queue
|
||||
if let Some(shader_jobs) = self.render_jobs.get_mut(&model.material.shader_id) {
|
||||
shader_jobs.push(job);
|
||||
} else {
|
||||
self.render_jobs.insert(model.material.shader_id, vec![job]);
|
||||
}
|
||||
|
||||
if self.buffer_storage.get(&entity).is_none() {
|
||||
let buffers = self.create_model_buffers(model);
|
||||
self.buffer_storage.insert(entity, buffers);
|
||||
} 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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>) {
|
||||
self.render_pipelines.insert(shader_id, pipeline);
|
||||
}
|
||||
|
||||
async fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
let jobs = &self.render_jobs;
|
||||
|
||||
let output = self.surface.get_current_texture()?;
|
||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
|
@ -199,9 +380,9 @@ impl Renderer for BasicRenderer {
|
|||
});
|
||||
|
||||
// Loop through all the render pipelines and draw the buffers.
|
||||
for pipeline in self.render_pipelines.iter() {
|
||||
for (shader_id, pipeline) in self.render_pipelines.iter() {
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Basic Renderer's Render Pass"),
|
||||
label: Some("Render Pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
|
@ -213,7 +394,34 @@ impl Renderer for BasicRenderer {
|
|||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
pipeline.render(&mut render_pass, 0..VERTICES.len() as u32, 0..1);
|
||||
render_pass.set_pipeline(pipeline.get_wgpu_pipeline());
|
||||
|
||||
let pipeline_jobs = jobs.get(shader_id);
|
||||
if let Some(jobs) = pipeline_jobs {
|
||||
for job in jobs.iter() {
|
||||
let mesh = job.mesh();
|
||||
let buffers = self.buffer_storage.get(&job.entity()).unwrap(); // TODO: create buffers if not made
|
||||
|
||||
if let Some(tex) = buffers.texture_bindgroup.as_ref() {
|
||||
render_pass.set_bind_group(0, &tex, &[]);
|
||||
}
|
||||
|
||||
render_pass.set_bind_group(1, &self.transform_bind_group, &[]);
|
||||
|
||||
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
|
||||
|
||||
render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
|
||||
render_pass.set_index_buffer(indices.buffer().slice(..), wgpu::IndexFormat::Uint16);
|
||||
render_pass.draw_indexed(0..indices_len, 0, 0..1);
|
||||
} else {
|
||||
render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
|
||||
render_pass.draw(0..mesh.vertices.len() as u32, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
//pipeline.render(&jobs, &mut render_pass, 0..VERTICES.len() as u32, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
self.queue.submit(std::iter::once(encoder.finish()));
|
||||
|
@ -234,8 +442,4 @@ impl Renderer for BasicRenderer {
|
|||
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
fn add_render_pipeline(&mut self, pipeline: FullRenderPipeline) {
|
||||
self.render_pipelines.push(pipeline);
|
||||
}
|
||||
}
|
|
@ -1,19 +1,42 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use image::GenericImageView;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub struct Texture {
|
||||
texture: wgpu::Texture,
|
||||
view: wgpu::TextureView,
|
||||
sampler: wgpu::Sampler,
|
||||
texture_id: u32,
|
||||
pub img: image::DynamicImage,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
|
||||
pub fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
|
||||
let img = image::load_from_memory(bytes)?;
|
||||
Self::from_image(device, queue, &img, Some(label))
|
||||
|
||||
Ok(Self {
|
||||
texture_id: 0,
|
||||
img,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str> ) -> anyhow::Result<Self> {
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct RenderTexture {
|
||||
texture_id: u32,
|
||||
texture: Arc<wgpu::Texture>,
|
||||
view: Arc<wgpu::TextureView>,
|
||||
sampler: Arc<wgpu::Sampler>,
|
||||
}
|
||||
|
||||
impl RenderTexture {
|
||||
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], texture_id: u32, label: &str) -> anyhow::Result<Self> {
|
||||
let img = image::load_from_memory(bytes)?;
|
||||
Self::from_image(device, queue, &img, texture_id, Some(label))
|
||||
}
|
||||
|
||||
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, texture_id: u32, label: Option<&str>) -> anyhow::Result<Self> {
|
||||
let rgba = img.to_rgba8();
|
||||
let dimensions = img.dimensions();
|
||||
|
||||
|
@ -64,10 +87,41 @@ impl Texture {
|
|||
}
|
||||
);
|
||||
|
||||
Ok(Self { texture, view, sampler })
|
||||
Ok(Self {
|
||||
texture_id,
|
||||
texture: Arc::new(texture),
|
||||
view: Arc::new(view),
|
||||
sampler: Arc::new(sampler),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &wgpu::Texture {
|
||||
pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Texture) {
|
||||
let rgba = texture.img.to_rgba8();
|
||||
let dimensions = texture.img.dimensions();
|
||||
let size = wgpu::Extent3d {
|
||||
width: dimensions.0,
|
||||
height: dimensions.1,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
|
||||
queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
texture: &self.texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn inner_texture(&self) -> &wgpu::Texture {
|
||||
&self.texture
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
use glam::Vec3;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Transform {
|
||||
matrix: glam::Mat4,
|
||||
}
|
||||
|
||||
impl Default for Transform {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
matrix: glam::Mat4::IDENTITY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Transform {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn from_glam(matrix: glam::Mat4) -> Self {
|
||||
Self {
|
||||
matrix,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
self.matrix *= translation;
|
||||
|
||||
self
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue