first rendering done
This commit is contained in:
parent
0f451c715c
commit
8b9e08f076
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target
|
||||
assets/models/bugatti/*
|
||||
|
||||
9
assets/models/bugatti/README.txt
Normal file
9
assets/models/bugatti/README.txt
Normal file
@ -0,0 +1,9 @@
|
||||
Hi, thanks for downloadiing this model.It was created by Bob Kimani (Kimz Auto).
|
||||
if you like the model please feel free to donate to my PayPal account at
|
||||
bobiankimani@gmail.com
|
||||
Or simply buy the model for a price of your choice here
|
||||
|
||||
https://sellfy.com/p/FrEB/
|
||||
I would reaaly appreciate it even if its just one dollar.Thanks;)
|
||||
Please include this credit when you use the file.
|
||||
Regards Bob :)
|
||||
400
assets/models/bugatti/bugatti.mtl
Normal file
400
assets/models/bugatti/bugatti.mtl
Normal file
@ -0,0 +1,400 @@
|
||||
# Blender MTL File: 'bugatti.blend'
|
||||
# Material Count: 40
|
||||
|
||||
newmtl BLUE.002
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.000000 0.000000 0.800000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl ENGINE
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl GRILL.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.026482 0.026482 0.026482
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mirrors
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl NAVY
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.000000 0.017778 0.047407
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl None
|
||||
Ns 0
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.8 0.8 0.8
|
||||
d 1
|
||||
illum 2
|
||||
|
||||
newmtl Nut.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Studio_Lights.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Studio_Lights.005
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Trim.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl WHEEL_CURB.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl WHITE.002
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl aluminiumm
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl back_drop.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.102592 0.102592 0.102592
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black_cable
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black_fuel_tank.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black_side_vent
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.001651 0.001651 0.001651
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black_strip.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.009774 0.009774 0.009774
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl black_vent.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl brake_disk.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl breaks_
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl cALLIPERS.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.014633 0.586055 0.640002
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl exhaust
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.204648 0.451652 0.640001
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl front_window.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl glass_front.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.054000 0.640003 0.568643
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl glossy
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.000000 0.568960 0.640002
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl headlight_glass.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl headlight_square.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl red.002
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl red_glass
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640002 0.047774 0.026908
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl reflective_coat.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.026482 0.026482 0.026482
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl rim_blue.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.026033 0.152250 0.640001
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl rim_silver.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl silver_door_strip.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.601480 0.265530
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl silver_trim
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.043975 0.043975 0.043975
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl sun
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl tyre.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.011736 0.011736 0.011736
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl wheel_joint.004
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl white_holders
|
||||
Ns 96.078431
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
@ -1,21 +1,74 @@
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::KeyEvent;
|
||||
use winit::keyboard::{Key, NamedKey};
|
||||
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||
use winit::window::WindowAttributes;
|
||||
use winit::{event, window};
|
||||
|
||||
use crate::backend::RenderBackend;
|
||||
use crate::app::scene::Scene;
|
||||
use crate::backend::{DrawCommand, RenderBackend};
|
||||
use crate::geometry::Mesh;
|
||||
use crate::handles::{MeshHandle, ShaderHandle};
|
||||
use crate::models::{self, ModelData};
|
||||
|
||||
pub enum UploadData<B: RenderBackend> {
|
||||
ModelData(ModelData),
|
||||
Shader(B::ShaderSource),
|
||||
}
|
||||
|
||||
pub struct App<B: RenderBackend> {
|
||||
backend: B,
|
||||
pub backend: B,
|
||||
pub scene: Scene,
|
||||
pub meshes: Vec<Mesh>,
|
||||
pub mesh_handles: Vec<MeshHandle>,
|
||||
pub model_queue: Vec<ModelData>,
|
||||
pub shader_queue: Vec<B::ShaderSource>,
|
||||
pub shaders: Vec<ShaderHandle>,
|
||||
}
|
||||
|
||||
impl<B: RenderBackend> App<B> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
backend: B::new(),
|
||||
scene: Default::default(),
|
||||
meshes: Vec::new(),
|
||||
mesh_handles: Vec::new(),
|
||||
shaders: Vec::new(),
|
||||
model_queue: Vec::new(),
|
||||
shader_queue: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_shader(&mut self, shader_src: B::ShaderSource) {
|
||||
self.shader_queue.push(shader_src);
|
||||
}
|
||||
|
||||
pub fn add_model(&mut self, model_data: ModelData) {
|
||||
self.model_queue.push(model_data);
|
||||
}
|
||||
|
||||
fn upload_data_queue(&mut self) {
|
||||
for mesh in &self.meshes {
|
||||
let handle = self.backend.create_mesh(mesh).expect("Should be able to create mesh");
|
||||
self.mesh_handles.push(handle);
|
||||
}
|
||||
let mut model: models::Model = Default::default();
|
||||
for shader_src in &self.shader_queue {
|
||||
let shader = self.backend.create_shader(&shader_src).expect("Should be able to create shaders");
|
||||
self.shaders.push(shader);
|
||||
}
|
||||
for model_data in &mut self.model_queue {
|
||||
for mesh in &mut model_data.meshes {
|
||||
let mat = model_data.materials.iter_mut().find(|mat| mat.name == *mesh.material_name.as_ref()
|
||||
.expect("Mesh should have associated Material!")
|
||||
).expect("Model should have Material requested by mesh");
|
||||
mat.shader = *self.shaders.get(0).expect("Should have a shader");
|
||||
let new_mesh = self.backend.create_mesh(mesh).unwrap();
|
||||
let mat_handle = self.scene.add_material(mat);
|
||||
model.parts.push((new_mesh, mat_handle))
|
||||
}
|
||||
model.set_transform(model_data.transform);
|
||||
}
|
||||
self.scene.models.push(model);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn window_attributes() -> WindowAttributes {
|
||||
@ -27,6 +80,7 @@ pub fn window_attributes() -> WindowAttributes {
|
||||
impl<B: RenderBackend> ApplicationHandler for App<B> {
|
||||
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
self.backend.resume(event_loop);
|
||||
self.upload_data_queue();
|
||||
}
|
||||
|
||||
fn suspended(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
@ -42,10 +96,25 @@ impl<B: RenderBackend> ApplicationHandler for App<B> {
|
||||
match event {
|
||||
event::WindowEvent::Resized(size) if size.width != 0 && size.height != 0 => {
|
||||
},
|
||||
event::WindowEvent::CloseRequested
|
||||
| event::WindowEvent::KeyboardInput { event: KeyEvent { logical_key: Key::Named(NamedKey::Escape), .. }, .. } => {
|
||||
event::WindowEvent::CloseRequested => {
|
||||
event_loop.exit();
|
||||
}
|
||||
event::WindowEvent::KeyboardInput { event, .. } => {
|
||||
println!("Hit key: {:#?}", &event.physical_key);
|
||||
match event.physical_key {
|
||||
PhysicalKey::Code(KeyCode::KeyW) => {
|
||||
self.scene.camera.position.z -= 0.1;
|
||||
}
|
||||
PhysicalKey::Code(KeyCode::KeyS) => {
|
||||
self.scene.camera.position.z += 0.1;
|
||||
}
|
||||
PhysicalKey::Code(KeyCode::Escape) => {
|
||||
event_loop.exit();
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
@ -63,5 +132,16 @@ impl<B: RenderBackend> ApplicationHandler for App<B> {
|
||||
}
|
||||
|
||||
fn about_to_wait(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
self.backend.begin_frame();
|
||||
for mesh in &self.mesh_handles {
|
||||
let cmd = DrawCommand {
|
||||
mesh: mesh.clone(),
|
||||
shader: ShaderHandle(0),
|
||||
textures: &[],
|
||||
uniforms: &[]
|
||||
};
|
||||
self.backend.draw(&cmd);
|
||||
}
|
||||
self.backend.end_frame();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,35 @@
|
||||
pub struct Camera {
|
||||
use crate::math::{Mat4, Vec3};
|
||||
|
||||
pub struct Camera {
|
||||
pub position: Vec3,
|
||||
pub target: Vec3,
|
||||
pub up: Vec3,
|
||||
pub fov: f32,
|
||||
pub aspect_ratio: f32,
|
||||
pub near: f32,
|
||||
pub far: f32,
|
||||
}
|
||||
|
||||
impl Default for Camera {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
position: Vec3::new(0.0, 2.0, 5.0),
|
||||
target: Vec3::new(0.0, 0.0, 0.0),
|
||||
up: Vec3::new(0.0, 1.0, 0.0),
|
||||
fov: 45.0_f32.to_radians(),
|
||||
aspect_ratio: 16.0 / 9.0,
|
||||
near: 0.1,
|
||||
far: 100.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
pub fn view_matrix(&self) -> Mat4 {
|
||||
Mat4::look_at(self.position, self.target, self.up)
|
||||
}
|
||||
|
||||
pub fn projection_matrix(&self) -> Mat4 {
|
||||
Mat4::perspective(self.fov, self.aspect_ratio, self.near, self.far)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,15 @@
|
||||
pub struct Light {
|
||||
use crate::math::Vec3;
|
||||
|
||||
pub struct Light {
|
||||
pub position: Vec3,
|
||||
pub color: Vec3,
|
||||
}
|
||||
|
||||
impl Default for Light {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
position: Vec3::new(3.0, 5.0, 3.0),
|
||||
color: Vec3::new(1.0, 1.0, 1.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,74 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{app::{camera::Camera, light::Light}, assets, backend::{backend, opengl::GlDrawCommand}, handles, models::Model};
|
||||
use crate::{app::{camera::Camera, light::Light}, assets, backend::{Uniform, backend}, handles, math::Mat4, models::Model};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Scene {
|
||||
pub light: Light,
|
||||
pub camera: Camera,
|
||||
pub models: Vec<Model>,
|
||||
pub materials: HashMap<handles::MaterialHandle, assets::mtl::Material>
|
||||
pub materials: HashMap<handles::MaterialHandle, assets::mtl::Material>,
|
||||
next_mat_id: u32,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
light: Light {},
|
||||
camera: Camera {},
|
||||
light: Light::default(),
|
||||
camera: Camera::default(),
|
||||
materials: HashMap::new(),
|
||||
next_mat_id: 0,
|
||||
models: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, backend: &impl backend::RenderBackend) {
|
||||
for model in &self.models {
|
||||
pub fn add_material(&mut self, material: &assets::mtl::Material) -> handles::MaterialHandle {
|
||||
let mat_handle = handles::MaterialHandle(self.next_mat_id);
|
||||
self.materials.insert(mat_handle, material.clone());
|
||||
self.next_mat_id += 1;
|
||||
mat_handle
|
||||
}
|
||||
|
||||
pub fn render(&mut self, backend: &mut impl backend::RenderBackend) {
|
||||
backend.begin_frame();
|
||||
|
||||
let view = self.camera.view_matrix();
|
||||
let projection = self.camera.projection_matrix();
|
||||
|
||||
let scene_uniforms = [
|
||||
Uniform::Mat4(c"u_view".into(), view),
|
||||
Uniform::Mat4(c"u_projection".into(), projection),
|
||||
Uniform::Vec3(c"u_view_pos".into(), self.camera.position),
|
||||
Uniform::Vec3(c"u_light_pos".into(), self.light.position),
|
||||
Uniform::Vec3(c"u_light_color".into(), self.light.color),
|
||||
];
|
||||
|
||||
for model in &mut self.models {
|
||||
let current_transform = model.transform;
|
||||
let transform = current_transform
|
||||
* Mat4::rotation_y(0.05);
|
||||
|
||||
model.set_transform(transform);
|
||||
|
||||
let model_uniform = Uniform::Mat4(c"u_model".into(), model.transform);
|
||||
|
||||
for (mesh, mtl) in &model.parts {
|
||||
let mtl = &self.materials[&mtl];
|
||||
let draw_cmd = GlDrawCommand {
|
||||
|
||||
let mut all_uniforms = vec![model_uniform.clone()];
|
||||
all_uniforms.extend(scene_uniforms.iter().cloned());
|
||||
all_uniforms.extend(mtl.uniforms().iter().cloned());
|
||||
|
||||
let draw_cmd = backend::DrawCommand {
|
||||
mesh: *mesh,
|
||||
shader: mtl.shader,
|
||||
uniforms: mtl.to_uniforms(),
|
||||
textures: None,
|
||||
uniforms: &all_uniforms,
|
||||
textures: &vec![],
|
||||
};
|
||||
|
||||
backend.draw(&draw_cmd);
|
||||
}
|
||||
}
|
||||
backend.end_frame();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,41 +1,153 @@
|
||||
use crate::{assets::{error::AssetError, parser::parse_args}, backend::opengl::Uniform, math::Vec3, shaders::ShaderHandle};
|
||||
use core::ffi;
|
||||
|
||||
use crate::{assets::{error::AssetError, parser::parse_args}, backend::Uniform, handles::ShaderHandle, math::{Mat4, Vec3, Vec4, Vec2}};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TextureId(pub u32);
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Material {
|
||||
pub name: String,
|
||||
pub shader: ShaderHandle,
|
||||
|
||||
pub ambient: Vec3,
|
||||
pub diffuse: Vec3,
|
||||
pub specular: Vec3,
|
||||
pub emissive: Vec3,
|
||||
pub shininess: f32,
|
||||
pub opacity: f32,
|
||||
ambient: Vec3,
|
||||
diffuse: Vec3,
|
||||
specular: Vec3,
|
||||
emissive: Vec3,
|
||||
_shininess: f32,
|
||||
opacity: f32,
|
||||
|
||||
pub diffuse_texture: Option<TextureId>,
|
||||
pub normal_texture: Option<TextureId>,
|
||||
pub specular_texture: Option<TextureId>,
|
||||
|
||||
uniforms: Vec<Uniform>,
|
||||
textures: Vec<TextureId>,
|
||||
}
|
||||
|
||||
impl Default for Material {
|
||||
fn default() -> Self {
|
||||
let mut mat = Self {
|
||||
name: String::new(),
|
||||
shader: ShaderHandle::default(),
|
||||
ambient: Vec3::new(0.1, 0.1, 0.1),
|
||||
diffuse: Vec3::new(0.8, 0.8, 0.8),
|
||||
specular: Vec3::new(0.5, 0.5, 0.5),
|
||||
emissive: Vec3::new(0.0, 0.0, 0.0),
|
||||
_shininess: 32.0,
|
||||
opacity: 1.0,
|
||||
diffuse_texture: None,
|
||||
normal_texture: None,
|
||||
specular_texture: None,
|
||||
uniforms: Vec::new(),
|
||||
textures: Vec::new(),
|
||||
};
|
||||
// Set default uniforms
|
||||
mat.set_uniform_v3(c"u_ambient", mat.ambient);
|
||||
mat.set_uniform_v3(c"u_diffuse", mat.diffuse);
|
||||
mat.set_uniform_v3(c"u_specular", mat.specular);
|
||||
mat.set_uniform_f(c"u_shininess", mat._shininess);
|
||||
mat
|
||||
}
|
||||
}
|
||||
|
||||
impl Material {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn to_uniforms(&self) -> [Uniform; 8] {
|
||||
[
|
||||
Uniform::Vec3(c"u_ambient".into(), self.ambient),
|
||||
Uniform::Vec3(c"u_diffuse".into(), self.diffuse),
|
||||
Uniform::Vec3(c"u_specular".into(), self.specular),
|
||||
Uniform::Float(c"u_shininess".into(), self.shininess),
|
||||
Uniform::None,
|
||||
Uniform::None,
|
||||
Uniform::None,
|
||||
Uniform::None,
|
||||
]
|
||||
pub fn set_ambient(&mut self, v: Vec3) {
|
||||
self.ambient = v;
|
||||
self.set_uniform_v3(c"u_ambient", v);
|
||||
}
|
||||
|
||||
pub fn set_diffuse(&mut self, v: Vec3) {
|
||||
self.diffuse = v;
|
||||
self.set_uniform_v3(c"u_diffuse", v);
|
||||
}
|
||||
|
||||
pub fn set_specular(&mut self, v: Vec3) {
|
||||
self.specular = v;
|
||||
self.set_uniform_v3(c"u_specular", v);
|
||||
}
|
||||
|
||||
pub fn set_emissive(&mut self, v: Vec3) {
|
||||
self.emissive = v;
|
||||
self.set_uniform_v3(c"u_emissive", v);
|
||||
}
|
||||
|
||||
pub fn set_shininess(&mut self, v: f32) {
|
||||
self._shininess = v;
|
||||
self.set_uniform_f(c"u_shininess", v);
|
||||
}
|
||||
|
||||
pub fn set_opacity(&mut self, v: f32) {
|
||||
self.opacity = v;
|
||||
self.set_uniform_f(c"u_opacity", v);
|
||||
}
|
||||
|
||||
|
||||
pub fn set_uniform_f(&mut self, name: &ffi::CStr, val: f32) {
|
||||
if let Some(Uniform::Float(_, v)) = self.uniforms
|
||||
.iter_mut()
|
||||
.find(|u| matches!(u, Uniform::Float(n, _) if n == name))
|
||||
{
|
||||
*v = val;
|
||||
} else {
|
||||
self.uniforms.push(Uniform::Float(name.into(), val));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_v2(&mut self, name: &ffi::CStr, val: Vec2) {
|
||||
if let Some(Uniform::Vec2(_, v)) = self.uniforms
|
||||
.iter_mut()
|
||||
.find(|u| matches!(u, Uniform::Vec2(n, _) if n == name))
|
||||
{
|
||||
*v = val;
|
||||
} else {
|
||||
self.uniforms.push(Uniform::Vec2(name.into(), val));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_v3(&mut self, name: &ffi::CStr, val: Vec3) {
|
||||
if let Some(Uniform::Vec3(_, v)) = self.uniforms
|
||||
.iter_mut()
|
||||
.find(|u| matches!(u, Uniform::Vec3(n, _) if n == name))
|
||||
{
|
||||
*v = val;
|
||||
} else {
|
||||
self.uniforms.push(Uniform::Vec3(name.into(), val));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_v4(&mut self, name: &ffi::CStr, val: Vec4) {
|
||||
if let Some(Uniform::Vec4(_, v)) = self.uniforms
|
||||
.iter_mut()
|
||||
.find(|u| matches!(u, Uniform::Vec4(n, _) if n == name))
|
||||
{
|
||||
*v = val;
|
||||
} else {
|
||||
self.uniforms.push(Uniform::Vec4(name.into(), val));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_m4(&mut self, name: &ffi::CStr, val: Mat4) {
|
||||
if let Some(Uniform::Mat4(_, v)) = self.uniforms
|
||||
.iter_mut()
|
||||
.find(|u| matches!(u, Uniform::Mat4(n, _) if n == name))
|
||||
{
|
||||
*v = val;
|
||||
} else {
|
||||
self.uniforms.push(Uniform::Mat4(name.into(), val));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uniforms(&self) -> &[Uniform] {
|
||||
&self.uniforms
|
||||
}
|
||||
|
||||
pub fn textures(&self) -> &[TextureId] {
|
||||
&self.textures
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +183,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
match key.trim() {
|
||||
"Ka" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(v) => material.ambient = Vec3(v),
|
||||
Ok([x, y, z]) => material.set_ambient(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -81,7 +193,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
},
|
||||
"Kd" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(v) => material.diffuse = Vec3(v),
|
||||
Ok([x, y, z]) => material.set_diffuse(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -91,7 +203,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
},
|
||||
"Ks" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(v) => material.specular = Vec3(v),
|
||||
Ok([x, y, z]) => material.set_specular(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -101,7 +213,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
},
|
||||
"Ke" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(v) => material.emissive = Vec3(v),
|
||||
Ok([x, y, z]) => material.set_emissive(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -111,7 +223,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
}
|
||||
"Ns" => {
|
||||
match parse_args::<1, f32>(values, delim) {
|
||||
Ok(v) => material.shininess = v[0],
|
||||
Ok(v) => material.set_shininess(v[0]),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -121,7 +233,7 @@ pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||
},
|
||||
"d" => {
|
||||
match parse_args::<1, f32>(values, delim) {
|
||||
Ok(v) => material.opacity = v[0],
|
||||
Ok(v) => material.set_opacity(v[0]),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
|
||||
@ -22,7 +22,7 @@ pub fn load_obj(path: &str) -> Result<types::ObjData, AssetError> {
|
||||
match prefix.trim() {
|
||||
"v" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(vec) => obj_data.vertices.push(Vec3(vec)),
|
||||
Ok([x, y, z]) => obj_data.vertices.push(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -32,7 +32,7 @@ pub fn load_obj(path: &str) -> Result<types::ObjData, AssetError> {
|
||||
},
|
||||
"vt" => {
|
||||
match parse_args::<2, f32>(values, delim) {
|
||||
Ok(vec) => obj_data.tex_coords.push(Vec2(vec)),
|
||||
Ok([x, y]) => obj_data.tex_coords.push(Vec2::new(x, y)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
@ -42,7 +42,7 @@ pub fn load_obj(path: &str) -> Result<types::ObjData, AssetError> {
|
||||
},
|
||||
"vn" => {
|
||||
match parse_args::<3, f32>(values, delim) {
|
||||
Ok(vec) => obj_data.normals.push(Vec3(vec)),
|
||||
Ok([x, y, z]) => obj_data.normals.push(Vec3::new(x, y, z)),
|
||||
Err(e) => return Err(AssetError::Parse {
|
||||
file: path.to_string(),
|
||||
line: i,
|
||||
|
||||
@ -1,27 +1,43 @@
|
||||
use crate::shaders;
|
||||
use crate::{geometry, handles::{self, MeshHandle}, math};
|
||||
use std::ffi::CString;
|
||||
|
||||
|
||||
pub struct DrawCommand<'a> {
|
||||
pub mesh: handles::MeshHandle,
|
||||
pub shader: handles::ShaderHandle,
|
||||
pub uniforms: &'a [Uniform],
|
||||
pub textures: &'a [(u32, u32)],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Uniform {
|
||||
Float(CString, f32),
|
||||
Vec2(CString, math::Vec2),
|
||||
Vec3(CString, math::Vec3),
|
||||
Vec4(CString, math::Vec4),
|
||||
Mat4(CString, math::Mat4),
|
||||
Int(CString, i32)
|
||||
}
|
||||
|
||||
pub trait RenderBackend {
|
||||
type ShaderSource;
|
||||
type DrawCommand;
|
||||
fn new() -> Self where Self: Sized;
|
||||
type ShaderSource: Default;
|
||||
fn new() -> Self;
|
||||
|
||||
fn resume(&mut self, event_loop: &winit::event_loop::ActiveEventLoop);
|
||||
fn resize(&mut self, width: u32, height: u32);
|
||||
fn draw(&self, cmd: &Self::DrawCommand);
|
||||
fn suspend(&mut self);
|
||||
|
||||
// // Frame
|
||||
// fn begin_frame(&mut self) -> FrameContext;
|
||||
// fn end_frame(&mut self);
|
||||
//
|
||||
// // Resources
|
||||
fn create_shader(&mut self, desc: Self::ShaderSource) -> Result<shaders::ShaderHandle, String>;
|
||||
fn begin_frame(&mut self);
|
||||
fn draw(&self, cmd: &DrawCommand);
|
||||
fn end_frame(&self);
|
||||
|
||||
fn create_shader(&mut self, desc: &Self::ShaderSource) -> Result<handles::ShaderHandle, String>;
|
||||
fn create_mesh(&mut self, mesh: &geometry::Mesh) -> Result<MeshHandle, String>;
|
||||
// fn create_buffer(&mut self, data: &[u8], usage: BufferUsage) -> BufferHandle;
|
||||
// fn create_texture(&mut self, desc: TextureDescriptor) -> TextureHandle;
|
||||
//
|
||||
// // Material = shader + uniforms + textures bundled
|
||||
// fn create_material(&mut self, shader: ShaderHandle) -> MaterialHandle;
|
||||
// fn set_material_param(&mut self, material: MaterialHandle, name: &str, value: UniformValue);
|
||||
|
||||
fn set_target_fps(&mut self, fps: u32);
|
||||
|
||||
}
|
||||
|
||||
// pub struct FrameContext<'a> {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
pub struct GpuMesh {
|
||||
pub vao: gl::types::GLuint,
|
||||
pub vbo: gl::types::GLuint,
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
|
||||
|
||||
use std::ffi::CString;
|
||||
|
||||
pub use Gles2 as Gl;
|
||||
pub use crate::math;
|
||||
|
||||
@ -14,25 +12,6 @@ use glutin::prelude::GlDisplay;
|
||||
use raw_window_handle::HasWindowHandle;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::handles::MeshHandle;
|
||||
use crate::shaders::ShaderHandle;
|
||||
|
||||
pub enum Uniform {
|
||||
Float(CString, f32),
|
||||
Vec3(CString, math::Vec3),
|
||||
Vec4(CString, math::Vec4),
|
||||
Mat4(CString, math::Mat4),
|
||||
Int(CString, i32),
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct GlDrawCommand {
|
||||
pub mesh: MeshHandle,
|
||||
pub shader: ShaderHandle,
|
||||
pub uniforms: [Uniform; 8],
|
||||
pub textures: Option<Vec<(u32, u32)>>,
|
||||
}
|
||||
|
||||
pub fn gl_config_picker(configs: Box<dyn Iterator<Item = Config> + '_>) -> Config {
|
||||
configs
|
||||
.reduce(|accum, config| {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::num::NonZero;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use glutin::config::GetGlConfig;
|
||||
use glutin::display::GetGlDisplay;
|
||||
use glutin::prelude::{GlDisplay, NotCurrentGlContext, PossiblyCurrentGlContext};
|
||||
@ -8,15 +10,17 @@ use glutin_winit::GlWindow;
|
||||
use winit::window::Window;
|
||||
use crate::backend::gpu;
|
||||
|
||||
use crate::{backend, handles, shaders};
|
||||
use crate::{backend, geometry, handles, shaders};
|
||||
use crate::app::app::window_attributes;
|
||||
use crate::backend::opengl::{self, GlRenderer};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GlDisplayCreationState {
|
||||
Builder(glutin_winit::DisplayBuilder),
|
||||
Init
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AppState {
|
||||
gl_surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
|
||||
window: Window,
|
||||
@ -29,16 +33,23 @@ pub struct GlBackend {
|
||||
template: glutin::config::ConfigTemplateBuilder,
|
||||
state: Option<AppState>,
|
||||
meshes: HashMap<handles::MeshHandle, gpu::GpuMesh>,
|
||||
shaders: HashMap<shaders::ShaderHandle, shaders::Shader>,
|
||||
shaders: HashMap<handles::ShaderHandle, shaders::Shader>,
|
||||
|
||||
// tmp
|
||||
next_mesh_id: u32,
|
||||
next_shader_id: u32,
|
||||
|
||||
frame_time: Duration,
|
||||
start: Instant,
|
||||
}
|
||||
|
||||
impl backend::RenderBackend for GlBackend {
|
||||
type DrawCommand = opengl::GlDrawCommand;
|
||||
type ShaderSource = opengl::GlShaderSource;
|
||||
|
||||
fn new() -> Self where Self: Sized {
|
||||
let template = glutin::config::ConfigTemplateBuilder::new()
|
||||
.with_alpha_size(8)
|
||||
.with_multisampling(4)
|
||||
.with_transparency(cfg!(target_os = "macos"));
|
||||
|
||||
let display_builder = glutin_winit::DisplayBuilder::new().with_window_attributes(Some(window_attributes()));
|
||||
@ -50,7 +61,11 @@ impl backend::RenderBackend for GlBackend {
|
||||
gl: None,
|
||||
meshes: HashMap::new(),
|
||||
shaders: HashMap::new(),
|
||||
template
|
||||
next_mesh_id: 0,
|
||||
next_shader_id: 0,
|
||||
frame_time: Duration::from_secs_f32(1.0 / 60.0),
|
||||
start: Instant::now(),
|
||||
template,
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,6 +127,8 @@ impl backend::RenderBackend for GlBackend {
|
||||
eprintln!("Error setting vsync: {:?}", res)
|
||||
}
|
||||
|
||||
window.request_redraw();
|
||||
|
||||
assert!(self.state.replace(AppState { gl_surface, window }).is_none());
|
||||
}
|
||||
|
||||
@ -141,23 +158,70 @@ impl backend::RenderBackend for GlBackend {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_shader(&mut self, desc: Self::ShaderSource) -> Result<shaders::ShaderHandle, String> {
|
||||
fn create_shader(&mut self, desc: &Self::ShaderSource) -> Result<handles::ShaderHandle, String> {
|
||||
if let Some(gl) = &self.gl {
|
||||
let shader = gl.create_shader(&desc);
|
||||
let shader_handle = self.shaders.len() as u32;
|
||||
let shader_handle = handles::ShaderHandle(self.next_shader_id);
|
||||
self.shaders.insert(shader_handle, shader);
|
||||
self.next_shader_id += 1;
|
||||
Ok(shader_handle)
|
||||
} else {
|
||||
todo!("implement error type for GlBackend")
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, cmd: &Self::DrawCommand) {
|
||||
fn create_mesh(&mut self, mesh: &geometry::Mesh) -> Result<handles::MeshHandle, String> {
|
||||
if let Some(gl) = &self.gl {
|
||||
let gpu_mesh = gl.upload_mesh(mesh);
|
||||
let mesh_handle = handles::MeshHandle(self.next_mesh_id);
|
||||
self.meshes.insert(mesh_handle, gpu_mesh);
|
||||
self.next_mesh_id += 1;
|
||||
Ok(mesh_handle)
|
||||
} else {
|
||||
todo!("implement error type for GlBackend")
|
||||
}
|
||||
}
|
||||
|
||||
fn begin_frame(&mut self) {
|
||||
if let Some(gl) = &self.gl {
|
||||
gl.clear(0.1, 0.1, 0.1, 1.0);
|
||||
self.start = Instant::now();
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, cmd: &backend::DrawCommand) {
|
||||
let mesh = self.meshes.get(&cmd.mesh);
|
||||
let shader = self.shaders.get(&cmd.shader);
|
||||
|
||||
if let (Some(mesh), Some(shader)) = (mesh, shader) {
|
||||
if let (Some(mesh), Some(shader), Some(gl)) = (mesh, shader, &self.gl) {
|
||||
gl.use_shader(*shader);
|
||||
|
||||
for u in cmd.uniforms {
|
||||
gl.apply_uniform(*shader, &u);
|
||||
}
|
||||
|
||||
gl.draw_mesh(mesh);
|
||||
|
||||
} else {
|
||||
println!("{:#?}", mesh);
|
||||
println!("{:#?}", shader);
|
||||
println!("{:#?}", self.state);
|
||||
println!("{:#?}", self.gl.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
fn end_frame(&self) {
|
||||
if let (Some(state), Some(gl_context)) = (&self.state, &self.gl_context) {
|
||||
state.window.request_redraw();
|
||||
state.gl_surface.swap_buffers(gl_context).unwrap();
|
||||
let elapsed = self.start.elapsed();
|
||||
if elapsed < self.frame_time {
|
||||
thread::sleep(self.frame_time - elapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_target_fps(&mut self, fps: u32) {
|
||||
self.frame_time = Duration::from_secs_f32(1.0 / (fps as f32));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use gl::types::GLfloat;
|
||||
use glutin::prelude::GlDisplay;
|
||||
use crate::backend::opengl::{self, Uniform};
|
||||
use crate::backend::{opengl, Uniform};
|
||||
use crate::math::{ Mat4, Vec3 };
|
||||
use crate::{geometry, backend::gpu::GpuMesh};
|
||||
use crate::shaders::Shader;
|
||||
use std::ops::Deref;
|
||||
use std::ffi::{ CStr, CString };
|
||||
use std::ffi::{ CStr, CString, c_void };
|
||||
use super::gl::Gl;
|
||||
|
||||
/// Render state containing camera and lighting information
|
||||
#[derive(Debug)]
|
||||
pub struct RenderState {
|
||||
pub projection: Mat4,
|
||||
pub view: Mat4,
|
||||
@ -18,18 +20,18 @@ pub struct RenderState {
|
||||
|
||||
impl RenderState {
|
||||
pub fn new(aspect_ratio: f32) -> Self {
|
||||
let camera_pos = Vec3([0.0, 2.0, 5.0]);
|
||||
let camera_pos = Vec3::new(0.0, 2.0, 5.0);
|
||||
Self {
|
||||
projection: Mat4::perspective(45.0_f32.to_radians(), aspect_ratio, 0.1, 100.0),
|
||||
view: Mat4::look_at(
|
||||
camera_pos,
|
||||
Vec3 ([0.0, 0.0, 0.0]),
|
||||
Vec3 ([0.0, 1.0, 0.0]),
|
||||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
),
|
||||
model: Mat4::identity(),
|
||||
camera_pos,
|
||||
light_pos: Vec3([3.0, 5.0, 3.0]),
|
||||
light_color: Vec3([1.0, 1.0, 1.0]),
|
||||
light_pos: Vec3::new(3.0, 5.0, 3.0),
|
||||
light_color: Vec3::new(1.0, 1.0, 1.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,7 +44,7 @@ fn get_gl_string(gl: &opengl::Gl, variant: gl::types::GLenum) -> Option<&'static
|
||||
}
|
||||
|
||||
pub struct GlRenderer {
|
||||
gl: std::rc::Rc<opengl::Gl>,
|
||||
gl: Gl,
|
||||
}
|
||||
|
||||
impl GlRenderer {
|
||||
@ -64,14 +66,15 @@ impl GlRenderer {
|
||||
println!("Shaders version on {}", shaders_version.to_string_lossy());
|
||||
}
|
||||
|
||||
// Enable depth testing for 3D rendering
|
||||
unsafe {
|
||||
gl.Enable(gl::DEPTH_TEST);
|
||||
gl.DepthFunc(gl::LESS);
|
||||
|
||||
gl.Enable(gl::MULTISAMPLE);
|
||||
}
|
||||
|
||||
Self {
|
||||
gl: std::rc::Rc::new(gl),
|
||||
gl
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,43 +86,30 @@ impl GlRenderer {
|
||||
gl.GenVertexArrays(1, &mut vao);
|
||||
gl.BindVertexArray(vao);
|
||||
|
||||
// Upload vertex data (position, normal, texcoord)
|
||||
let mut vbo = std::mem::zeroed();
|
||||
gl.GenBuffers(1, &mut vbo);
|
||||
gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
|
||||
|
||||
// Vertex layout: [pos.x, pos.y, pos.z, norm.x, norm.y, norm.z, tex.x, tex.y]
|
||||
let vertex_data: Vec<f32> = mesh.vertices
|
||||
.iter()
|
||||
.flat_map(|v| [
|
||||
v.position.x(), v.position.y(), v.position.z(),
|
||||
v.normal.x(), v.normal.y(), v.normal.z(),
|
||||
v.tex_coord.x(), v.tex_coord.y(),
|
||||
])
|
||||
.collect();
|
||||
for attribute in &mesh.format.attributes {
|
||||
let location = attribute.semantic.location();
|
||||
gl.VertexAttribPointer(
|
||||
attribute.semantic.location(),
|
||||
attribute.comp_count as i32,
|
||||
attribute.data_type.to_gpu(),
|
||||
attribute.normalized as u8,
|
||||
mesh.format.stride as i32,
|
||||
attribute.offset as *const c_void,
|
||||
);
|
||||
gl.EnableVertexAttribArray(location);
|
||||
}
|
||||
|
||||
gl.BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(vertex_data.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr,
|
||||
vertex_data.as_ptr() as *const _,
|
||||
mesh.vertex_data.len() as gl::types::GLsizeiptr,
|
||||
mesh.vertex_data.as_ptr() as *const _,
|
||||
gl::STATIC_DRAW,
|
||||
);
|
||||
|
||||
let stride = 8 * std::mem::size_of::<f32>() as gl::types::GLsizei;
|
||||
|
||||
// Position attribute (location = 0)
|
||||
gl.VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, std::ptr::null());
|
||||
gl.EnableVertexAttribArray(0);
|
||||
|
||||
// Normal attribute (location = 1)
|
||||
gl.VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, stride, (3 * std::mem::size_of::<f32>()) as *const _);
|
||||
gl.EnableVertexAttribArray(1);
|
||||
|
||||
// Texcoord attribute (location = 2)
|
||||
gl.VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, stride, (6 * std::mem::size_of::<f32>()) as *const _);
|
||||
gl.EnableVertexAttribArray(2);
|
||||
|
||||
// Upload index data if available
|
||||
let (ebo, index_count) = if !mesh.indices.is_empty() {
|
||||
let mut ebo = std::mem::zeroed();
|
||||
gl.GenBuffers(1, &mut ebo);
|
||||
@ -141,7 +131,7 @@ impl GlRenderer {
|
||||
vao,
|
||||
vbo,
|
||||
ebo,
|
||||
vertex_count: mesh.vertices.len() as i32,
|
||||
vertex_count: mesh.vertex_count as i32,
|
||||
index_count,
|
||||
}
|
||||
}
|
||||
@ -183,34 +173,48 @@ impl GlRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_uniform(&self, shader: Shader, uniform: Uniform) {
|
||||
pub fn apply_uniform(&self, shader: Shader, uniform: &Uniform) {
|
||||
unsafe {
|
||||
match uniform {
|
||||
Uniform::Float(name, value) => {
|
||||
let location = self.GetUniformLocation(shader.0, name.as_ptr());
|
||||
self.Uniform1f(location, value);
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.Uniform1f(location, *value);
|
||||
}
|
||||
Uniform::Int(name, value) => {
|
||||
let location = self.GetUniformLocation(shader.0, name.as_ptr());
|
||||
self.Uniform1i(location, value);
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.Uniform1i(location, *value);
|
||||
}
|
||||
Uniform::Vec2(name, value) => {
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.Uniform2f(location, value[0], value[1]);
|
||||
}
|
||||
Uniform::Vec3(name, value) => {
|
||||
let location = self.GetUniformLocation(shader.0, name.as_ptr());
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.Uniform3f(location, value[0], value[1], value[2]);
|
||||
}
|
||||
Uniform::Vec4(name, value) => {
|
||||
let location = self.GetUniformLocation(shader.0, name.as_ptr());
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.Uniform4f(location, value[0], value[1], value[2], value[3]);
|
||||
}
|
||||
Uniform::Mat4(name, value) => {
|
||||
let location = self.GetUniformLocation(shader.0, name.as_ptr());
|
||||
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||
self.UniformMatrix4fv(location, 1, gl::FALSE, value.as_ptr());
|
||||
}
|
||||
Uniform::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self, red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {
|
||||
unsafe {
|
||||
self.ClearColor(red, green, blue, alpha);
|
||||
self.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_shader(&self, shader: Shader) {
|
||||
unsafe { self.UseProgram(*shader) };
|
||||
}
|
||||
|
||||
pub fn resize(&self, width: i32, height: i32) {
|
||||
unsafe {
|
||||
self.gl.Viewport(0, 0, width, height);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#[derive(Default)]
|
||||
pub struct GlShaderSource {
|
||||
pub vertex_src: String,
|
||||
pub fragment_src: String,
|
||||
|
||||
@ -1,18 +1,67 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::assets::types::{VertexIndex, ObjData, ObjMesh};
|
||||
|
||||
use crate::{assets::types::{ObjData, ObjMesh, VertexIndex}, geometry::VertexFormat, math::{Vec2, Vec4}};
|
||||
use super::Vertex;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Mesh {
|
||||
pub name: String,
|
||||
pub format: VertexFormat,
|
||||
pub vertex_data: Vec<u8>,
|
||||
pub vertex_count: usize,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u32>,
|
||||
pub material_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MeshBuilder {
|
||||
mesh: Mesh,
|
||||
current_vertex: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MeshBuilder {
|
||||
pub fn build(self) -> Mesh {
|
||||
self.mesh
|
||||
}
|
||||
|
||||
pub fn begin_vertex(mut self) -> Self {
|
||||
self.current_vertex.clear();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn end_vertex(mut self) -> Self {
|
||||
if self.current_vertex.len() > 0 {
|
||||
self.mesh.vertex_data.extend_from_slice(&self.current_vertex);
|
||||
self.mesh.vertex_count += 1;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn position2(mut self, pos: Vec2) -> Self {
|
||||
self.current_vertex.extend_from_slice(&pos.to_bytes());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tex_coord(mut self, pos: Vec2) -> Self {
|
||||
self.current_vertex.extend_from_slice(&pos.to_bytes());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: Vec4) -> Self {
|
||||
self.current_vertex.extend_from_slice(&color.to_bytes());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn builder(name: impl AsRef<str>, format: VertexFormat) -> MeshBuilder {
|
||||
let mesh: Self = Self { name: name.as_ref().to_string(), format, ..Default::default() };
|
||||
MeshBuilder {
|
||||
mesh,
|
||||
current_vertex: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(obj: &ObjData, obj_mash: &ObjMesh) -> Self {
|
||||
let mut vertices: Vec<Vertex> = Vec::new();
|
||||
let mut indices: Vec<u32> = Vec::new();
|
||||
@ -36,6 +85,9 @@ impl Mesh {
|
||||
}
|
||||
Mesh {
|
||||
vertices,
|
||||
format: Default::default(),
|
||||
vertex_data: vec![],
|
||||
vertex_count: 0,
|
||||
indices,
|
||||
name: obj_mash.name.clone(),
|
||||
material_name: obj_mash.material_name.clone(),
|
||||
|
||||
@ -1,5 +1,97 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::math::{ Vec2, Vec3 };
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VertexSemantic {
|
||||
Position,
|
||||
Normal,
|
||||
TexCoord0,
|
||||
TexCoord1,
|
||||
Color,
|
||||
}
|
||||
|
||||
impl VertexSemantic {
|
||||
pub fn location(&self) -> u32 {
|
||||
match self {
|
||||
VertexSemantic::Position => 0,
|
||||
VertexSemantic::Normal => 1,
|
||||
VertexSemantic::Color => 2,
|
||||
VertexSemantic::TexCoord0 => 3,
|
||||
VertexSemantic::TexCoord1 => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum AttributeType {
|
||||
Float,
|
||||
Int,
|
||||
UnsignedInt,
|
||||
Byte,
|
||||
UnsignedByte,
|
||||
}
|
||||
|
||||
impl AttributeType {
|
||||
pub fn to_gpu(&self) -> gl::types::GLenum {
|
||||
match self {
|
||||
AttributeType::Float => gl::FLOAT,
|
||||
AttributeType::Int => gl::INT,
|
||||
AttributeType::UnsignedInt => gl::UNSIGNED_INT,
|
||||
AttributeType::Byte => gl::BYTE,
|
||||
AttributeType::UnsignedByte => gl::UNSIGNED_BYTE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VertexAttribute {
|
||||
pub semantic: VertexSemantic,
|
||||
pub comp_count: usize,
|
||||
pub data_type: AttributeType,
|
||||
pub normalized: bool,
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VertexFormat {
|
||||
pub attributes: Vec<VertexAttribute>,
|
||||
pub stride: usize,
|
||||
}
|
||||
|
||||
impl VertexFormat {
|
||||
pub fn ui_2d() -> Self {
|
||||
Self {
|
||||
attributes: vec![
|
||||
VertexAttribute {
|
||||
semantic: VertexSemantic::Position,
|
||||
comp_count: 2,
|
||||
data_type: AttributeType::Float,
|
||||
normalized: false,
|
||||
offset: 0,
|
||||
},
|
||||
VertexAttribute {
|
||||
semantic: VertexSemantic::Color,
|
||||
comp_count: 4,
|
||||
data_type: AttributeType::Float,
|
||||
normalized: false,
|
||||
offset: 2 * std::mem::size_of::<f32>()
|
||||
}
|
||||
],
|
||||
stride: (2 + 4) * std::mem::size_of::<f32>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VertexFormat {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
attributes: vec![],
|
||||
stride: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Vertex {
|
||||
pub position: Vec3,
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct MeshHandle(pub u32);
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct MaterialHandle(pub u32);
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ShaderHandle(pub u32);
|
||||
|
||||
impl Deref for ShaderHandle {
|
||||
type Target = u32;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
pub mod models {
|
||||
|
||||
pub mod model;
|
||||
pub use model::*;
|
||||
}
|
||||
@ -53,6 +52,8 @@ pub mod shaders {
|
||||
|
||||
pub mod constants;
|
||||
pub use constants::*;
|
||||
|
||||
pub mod inputs;
|
||||
}
|
||||
|
||||
pub mod backend {
|
||||
|
||||
41
src/main.rs
41
src/main.rs
@ -1,37 +1,46 @@
|
||||
use proj::{
|
||||
app::app::App, assets, backend::opengl, shaders::{FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_SOURCE}
|
||||
app::app::App, assets, backend::opengl, geometry::{AttributeType, Mesh, MeshBuilder, VertexFormat, VertexSemantic}, math::{Mat4, Vec2, Vec4}, models::{self, Model}, shaders::{FRAGMENT_SHADER_2D, FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_2D, VERTEX_SHADER_SOURCE, inputs::ShaderInputs}
|
||||
};
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
const HOUSE_OBJ_PATH: &str = "assets/models/small_house/model.obj";
|
||||
const HOUSE_MAT_PATH: &str = "assets/models/small_house/materials.mtl";
|
||||
|
||||
const BUGATTI_OBJ_PATH: &str = "assets/models/bugatti/bugatti.obj";
|
||||
const BUGATTI_MTL_PATH: &str = "assets/models/bugatti/bugatti.mtl";
|
||||
|
||||
fn main() {
|
||||
dotenvy::dotenv().ok();
|
||||
|
||||
let event_loop = EventLoop::new()
|
||||
.expect("Should be able to have Event Loop");
|
||||
|
||||
let _shader_src = opengl::GlShaderSource {
|
||||
vertex_src: VERTEX_SHADER_SOURCE.to_string(),
|
||||
fragment_src: FRAGMENT_SHADER_SOURCE.to_string()
|
||||
let shader_src = opengl::GlShaderSource {
|
||||
vertex_src: VERTEX_SHADER_2D.to_string(),
|
||||
fragment_src: FRAGMENT_SHADER_2D.to_string(),
|
||||
};
|
||||
|
||||
// Load OBJ and materials (CPU-side, before GL context)
|
||||
let obj_data = match assets::obj::load_obj(HOUSE_OBJ_PATH) {
|
||||
Ok(o) => o,
|
||||
Err(e) => return eprintln!("Error loading OBJ: {}", e),
|
||||
};
|
||||
|
||||
let materials = match assets::mtl::load_materials(HOUSE_MAT_PATH) {
|
||||
Ok(m) => m,
|
||||
Err(e) => return eprintln!("Error loading materials: {}", e),
|
||||
};
|
||||
|
||||
println!("Loaded {} meshes, {} materials", obj_data.meshes.len(), materials.len());
|
||||
|
||||
let mut app = App::<opengl::GlBackend>::new();
|
||||
|
||||
let mesh = Mesh::builder("triangle", VertexFormat::ui_2d())
|
||||
.begin_vertex()
|
||||
.position2(Vec2::new(0.0, 0.5))
|
||||
.color(Vec4::new(1.0, 0.0, 0.0, 1.0))
|
||||
.end_vertex()
|
||||
.begin_vertex()
|
||||
.position2(Vec2::new(-0.5, -0.5))
|
||||
.color(Vec4::new(1.0, 1.0, 0.0, 1.0))
|
||||
.end_vertex()
|
||||
.begin_vertex()
|
||||
.position2(Vec2::new(0.5, -0.5))
|
||||
.color(Vec4::new(0.0, 0.0, 1.0, 1.0))
|
||||
.end_vertex()
|
||||
.build();
|
||||
|
||||
app.meshes.push(mesh);
|
||||
app.add_shader(shader_src);
|
||||
|
||||
let event_res = event_loop.run_app(&mut app);
|
||||
|
||||
println!("{:#?}", event_res);
|
||||
|
||||
@ -98,9 +98,9 @@ impl Mat4 {
|
||||
let u = r.cross(&f);
|
||||
Self {
|
||||
data: [
|
||||
r.x(), u.x(), -f.x(), 0.0,
|
||||
r.y(), u.y(), -f.y(), 0.0,
|
||||
r.z(), u.z(), -f.z(), 0.0,
|
||||
r.x, u.x, -f.x, 0.0,
|
||||
r.y, u.y, -f.y, 0.0,
|
||||
r.z, u.z, -f.z, 0.0,
|
||||
-r.dot(&eye), -u.dot(&eye), f.dot(&eye), 1.0,
|
||||
],
|
||||
}
|
||||
|
||||
@ -2,39 +2,26 @@ use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Vec2(pub [f32; 2]);
|
||||
pub struct Vec2 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl Vec2 {
|
||||
pub const fn new(x: f32, y: f32) -> Self {
|
||||
Self([x, y])
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Self {
|
||||
Self([0.0, 0.0])
|
||||
Self { x: 0.0, y: 0.0 }
|
||||
}
|
||||
|
||||
pub const fn one() -> Self {
|
||||
Self([1.0, 1.0])
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0[0]
|
||||
}
|
||||
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0[1]
|
||||
}
|
||||
|
||||
pub fn x_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[0]
|
||||
}
|
||||
|
||||
pub fn y_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[1]
|
||||
Self { x: 1.0, y: 1.0 }
|
||||
}
|
||||
|
||||
pub fn length_squared(&self) -> f32 {
|
||||
self.0[0] * self.0[0] + self.0[1] * self.0[1]
|
||||
self.x * self.x + self.y * self.y
|
||||
}
|
||||
|
||||
pub fn length(&self) -> f32 {
|
||||
@ -46,28 +33,40 @@ impl Vec2 {
|
||||
if len == 0.0 {
|
||||
return *self;
|
||||
}
|
||||
Self([self.0[0] / len, self.0[1] / len])
|
||||
Self {
|
||||
x: self.x / len,
|
||||
y: self.y / len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dot(&self, other: &Self) -> f32 {
|
||||
self.0[0] * other.0[0] + self.0[1] * other.0[1]
|
||||
self.x * other.x + self.y * other.y
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const f32 {
|
||||
self.0.as_ptr()
|
||||
&self.x as *const f32
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||
self.0.as_mut_ptr()
|
||||
&mut self.x as *mut f32
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 8] {
|
||||
let mut bytes = [0u8; 8];
|
||||
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
// Add operations
|
||||
impl Add for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] + rhs.0[0], self.0[1] + rhs.0[1]])
|
||||
Self {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,16 +74,21 @@ impl Add<f32> for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] + rhs, self.0[1] + rhs])
|
||||
Self {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subtraction operations
|
||||
impl Sub for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] - rhs.0[0], self.0[1] - rhs.0[1]])
|
||||
Self {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,16 +96,21 @@ impl Sub<f32> for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] - rhs, self.0[1] - rhs])
|
||||
Self {
|
||||
x: self.x - rhs,
|
||||
y: self.y - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplication operations
|
||||
impl Mul for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] * rhs.0[0], self.0[1] * rhs.0[1]])
|
||||
Self {
|
||||
x: self.x * rhs.x,
|
||||
y: self.y * rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,16 +118,21 @@ impl Mul<f32> for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] * rhs, self.0[1] * rhs])
|
||||
Self {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Division operations
|
||||
impl Div for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] / rhs.0[0], self.0[1] / rhs.0[1]])
|
||||
Self {
|
||||
x: self.x / rhs.x,
|
||||
y: self.y / rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,30 +140,42 @@ impl Div<f32> for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] / rhs, self.0[1] / rhs])
|
||||
Self {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negation
|
||||
impl Neg for Vec2 {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self([-self.0[0], -self.0[1]])
|
||||
Self {
|
||||
x: -self.x,
|
||||
y: -self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Index operations
|
||||
impl Index<usize> for Vec2 {
|
||||
type Output = f32;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.0[index]
|
||||
match index {
|
||||
0 => &self.x,
|
||||
1 => &self.y,
|
||||
_ => panic!("Vec2 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec2 {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.0[index]
|
||||
match index {
|
||||
0 => &mut self.x,
|
||||
1 => &mut self.y,
|
||||
_ => panic!("Vec2 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,47 +2,27 @@ use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Vec3(pub [f32; 3]);
|
||||
pub struct Vec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
impl Vec3 {
|
||||
pub const fn new(x: f32, y: f32, z: f32) -> Self {
|
||||
Self([x, y, z])
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Self {
|
||||
Self([0.0, 0.0, 0.0])
|
||||
Self { x: 0.0, y: 0.0, z: 0.0 }
|
||||
}
|
||||
|
||||
pub const fn one() -> Self {
|
||||
Self([1.0, 1.0, 1.0])
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0[0]
|
||||
}
|
||||
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0[1]
|
||||
}
|
||||
|
||||
pub fn z(&self) -> f32 {
|
||||
self.0[2]
|
||||
}
|
||||
|
||||
pub fn x_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[0]
|
||||
}
|
||||
|
||||
pub fn y_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[1]
|
||||
}
|
||||
|
||||
pub fn z_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[2]
|
||||
Self { x: 1.0, y: 1.0, z: 1.0 }
|
||||
}
|
||||
|
||||
pub fn length_squared(&self) -> f32 {
|
||||
self.0[0] * self.0[0] + self.0[1] * self.0[1] + self.0[2] * self.0[2]
|
||||
self.x * self.x + self.y * self.y + self.z * self.z
|
||||
}
|
||||
|
||||
pub fn length(&self) -> f32 {
|
||||
@ -54,36 +34,51 @@ impl Vec3 {
|
||||
if len == 0.0 {
|
||||
return *self;
|
||||
}
|
||||
Self([self.0[0] / len, self.0[1] / len, self.0[2] / len])
|
||||
Self {
|
||||
x: self.x / len,
|
||||
y: self.y / len,
|
||||
z: self.z / len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dot(&self, other: &Self) -> f32 {
|
||||
self.0[0] * other.0[0] + self.0[1] * other.0[1] + self.0[2] * other.0[2]
|
||||
self.x * other.x + self.y * other.y + self.z * other.z
|
||||
}
|
||||
|
||||
pub fn cross(&self, other: &Self) -> Self {
|
||||
Self([
|
||||
self.0[1] * other.0[2] - self.0[2] * other.0[1],
|
||||
self.0[2] * other.0[0] - self.0[0] * other.0[2],
|
||||
self.0[0] * other.0[1] - self.0[1] * other.0[0],
|
||||
])
|
||||
Self {
|
||||
x: self.y * other.z - self.z * other.y,
|
||||
y: self.z * other.x - self.x * other.z,
|
||||
z: self.x * other.y - self.y * other.x,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const f32 {
|
||||
self.0.as_ptr()
|
||||
&self.x as *const f32
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||
self.0.as_mut_ptr()
|
||||
&mut self.x as *mut f32
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 12] {
|
||||
let mut bytes = [0u8; 12];
|
||||
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||
bytes[8..12].copy_from_slice(&self.z.to_ne_bytes());
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
// Add operations
|
||||
impl Add for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] + rhs.0[0], self.0[1] + rhs.0[1], self.0[2] + rhs.0[2]])
|
||||
Self {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,16 +86,23 @@ impl Add<f32> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] + rhs, self.0[1] + rhs, self.0[2] + rhs])
|
||||
Self {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
z: self.z + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subtraction operations
|
||||
impl Sub for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] - rhs.0[0], self.0[1] - rhs.0[1], self.0[2] - rhs.0[2]])
|
||||
Self {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,16 +110,23 @@ impl Sub<f32> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] - rhs, self.0[1] - rhs, self.0[2] - rhs])
|
||||
Self {
|
||||
x: self.x - rhs,
|
||||
y: self.y - rhs,
|
||||
z: self.z - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplication operations
|
||||
impl Mul for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] * rhs.0[0], self.0[1] * rhs.0[1], self.0[2] * rhs.0[2]])
|
||||
Self {
|
||||
x: self.x * rhs.x,
|
||||
y: self.y * rhs.y,
|
||||
z: self.z * rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,16 +134,23 @@ impl Mul<f32> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] * rhs, self.0[1] * rhs, self.0[2] * rhs])
|
||||
Self {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
z: self.z * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Division operations
|
||||
impl Div for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] / rhs.0[0], self.0[1] / rhs.0[1], self.0[2] / rhs.0[2]])
|
||||
Self {
|
||||
x: self.x / rhs.x,
|
||||
y: self.y / rhs.y,
|
||||
z: self.z / rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,30 +158,46 @@ impl Div<f32> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] / rhs, self.0[1] / rhs, self.0[2] / rhs])
|
||||
Self {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
z: self.z / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negation
|
||||
impl Neg for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self([-self.0[0], -self.0[1], -self.0[2]])
|
||||
Self {
|
||||
x: -self.x,
|
||||
y: -self.y,
|
||||
z: -self.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Index operations
|
||||
impl Index<usize> for Vec3 {
|
||||
type Output = f32;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.0[index]
|
||||
match index {
|
||||
0 => &self.x,
|
||||
1 => &self.y,
|
||||
2 => &self.z,
|
||||
_ => panic!("Vec3 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec3 {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.0[index]
|
||||
match index {
|
||||
0 => &mut self.x,
|
||||
1 => &mut self.y,
|
||||
2 => &mut self.z,
|
||||
_ => panic!("Vec3 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,55 +2,28 @@ use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Vec4(pub [f32; 4]);
|
||||
pub struct Vec4 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub w: f32,
|
||||
}
|
||||
|
||||
impl Vec4 {
|
||||
pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
|
||||
Self([x, y, z, w])
|
||||
Self { x, y, z, w }
|
||||
}
|
||||
|
||||
pub const fn zero() -> Self {
|
||||
Self([0.0, 0.0, 0.0, 0.0])
|
||||
Self { x: 0.0, y: 0.0, z: 0.0, w: 0.0 }
|
||||
}
|
||||
|
||||
pub const fn one() -> Self {
|
||||
Self([1.0, 1.0, 1.0, 1.0])
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0[0]
|
||||
}
|
||||
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0[1]
|
||||
}
|
||||
|
||||
pub fn z(&self) -> f32 {
|
||||
self.0[2]
|
||||
}
|
||||
|
||||
pub fn w(&self) -> f32 {
|
||||
self.0[3]
|
||||
}
|
||||
|
||||
pub fn x_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[0]
|
||||
}
|
||||
|
||||
pub fn y_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[1]
|
||||
}
|
||||
|
||||
pub fn z_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[2]
|
||||
}
|
||||
|
||||
pub fn w_mut(&mut self) -> &mut f32 {
|
||||
&mut self.0[3]
|
||||
Self { x: 1.0, y: 1.0, z: 1.0, w: 1.0 }
|
||||
}
|
||||
|
||||
pub fn length_squared(&self) -> f32 {
|
||||
self.0[0] * self.0[0] + self.0[1] * self.0[1] + self.0[2] * self.0[2] + self.0[3] * self.0[3]
|
||||
self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
|
||||
}
|
||||
|
||||
pub fn length(&self) -> f32 {
|
||||
@ -62,28 +35,46 @@ impl Vec4 {
|
||||
if len == 0.0 {
|
||||
return *self;
|
||||
}
|
||||
Self([self.0[0] / len, self.0[1] / len, self.0[2] / len, self.0[3] / len])
|
||||
Self {
|
||||
x: self.x / len,
|
||||
y: self.y / len,
|
||||
z: self.z / len,
|
||||
w: self.w / len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dot(&self, other: &Self) -> f32 {
|
||||
self.0[0] * other.0[0] + self.0[1] * other.0[1] + self.0[2] * other.0[2] + self.0[3] * other.0[3]
|
||||
self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const f32 {
|
||||
self.0.as_ptr()
|
||||
&self.x as *const f32
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||
self.0.as_mut_ptr()
|
||||
&mut self.x as *mut f32
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 16] {
|
||||
let mut bytes = [0u8; 16];
|
||||
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||
bytes[8..12].copy_from_slice(&self.z.to_ne_bytes());
|
||||
bytes[12..16].copy_from_slice(&self.w.to_ne_bytes());
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
// Add operations
|
||||
impl Add for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] + rhs.0[0], self.0[1] + rhs.0[1], self.0[2] + rhs.0[2], self.0[3] + rhs.0[3]])
|
||||
Self {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
w: self.w + rhs.w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,16 +82,25 @@ impl Add<f32> for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] + rhs, self.0[1] + rhs, self.0[2] + rhs, self.0[3] + rhs])
|
||||
Self {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
z: self.z + rhs,
|
||||
w: self.w + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subtraction operations
|
||||
impl Sub for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] - rhs.0[0], self.0[1] - rhs.0[1], self.0[2] - rhs.0[2], self.0[3] - rhs.0[3]])
|
||||
Self {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
w: self.w - rhs.w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,16 +108,25 @@ impl Sub<f32> for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] - rhs, self.0[1] - rhs, self.0[2] - rhs, self.0[3] - rhs])
|
||||
Self {
|
||||
x: self.x - rhs,
|
||||
y: self.y - rhs,
|
||||
z: self.z - rhs,
|
||||
w: self.w - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplication operations
|
||||
impl Mul for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] * rhs.0[0], self.0[1] * rhs.0[1], self.0[2] * rhs.0[2], self.0[3] * rhs.0[3]])
|
||||
Self {
|
||||
x: self.x * rhs.x,
|
||||
y: self.y * rhs.y,
|
||||
z: self.z * rhs.z,
|
||||
w: self.w * rhs.w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,16 +134,25 @@ impl Mul<f32> for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] * rhs, self.0[1] * rhs, self.0[2] * rhs, self.0[3] * rhs])
|
||||
Self {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
z: self.z * rhs,
|
||||
w: self.w * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Division operations
|
||||
impl Div for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self([self.0[0] / rhs.0[0], self.0[1] / rhs.0[1], self.0[2] / rhs.0[2], self.0[3] / rhs.0[3]])
|
||||
Self {
|
||||
x: self.x / rhs.x,
|
||||
y: self.y / rhs.y,
|
||||
z: self.z / rhs.z,
|
||||
w: self.w / rhs.w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,30 +160,50 @@ impl Div<f32> for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: f32) -> Self::Output {
|
||||
Self([self.0[0] / rhs, self.0[1] / rhs, self.0[2] / rhs, self.0[3] / rhs])
|
||||
Self {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
z: self.z / rhs,
|
||||
w: self.w / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negation
|
||||
impl Neg for Vec4 {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self([-self.0[0], -self.0[1], -self.0[2], -self.0[3]])
|
||||
Self {
|
||||
x: -self.x,
|
||||
y: -self.y,
|
||||
z: -self.z,
|
||||
w: -self.w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Index operations
|
||||
impl Index<usize> for Vec4 {
|
||||
type Output = f32;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.0[index]
|
||||
match index {
|
||||
0 => &self.x,
|
||||
1 => &self.y,
|
||||
2 => &self.z,
|
||||
3 => &self.w,
|
||||
_ => panic!("Vec4 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec4 {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.0[index]
|
||||
match index {
|
||||
0 => &mut self.x,
|
||||
1 => &mut self.y,
|
||||
2 => &mut self.z,
|
||||
3 => &mut self.w,
|
||||
_ => panic!("Vec4 index out of bounds: {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,13 @@ use crate::geometry::Mesh;
|
||||
use crate::assets::mtl::Material;
|
||||
use crate::handles::{ MeshHandle, MaterialHandle };
|
||||
use crate::assets::types::ObjData;
|
||||
use crate::math::Mat4;
|
||||
|
||||
pub struct ModelData {
|
||||
pub name: String,
|
||||
pub meshes: Vec<Mesh>,
|
||||
pub materials: Vec<Material>,
|
||||
pub transform: Mat4,
|
||||
}
|
||||
|
||||
impl From<&ObjData> for ModelData {
|
||||
@ -19,11 +21,41 @@ impl From<&ObjData> for ModelData {
|
||||
name: String::new(),
|
||||
meshes,
|
||||
materials: Vec::new(),
|
||||
transform: Mat4::identity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Model {
|
||||
pub name: String,
|
||||
pub parts: Vec<(MeshHandle, MaterialHandle)>,
|
||||
pub transform: Mat4,
|
||||
}
|
||||
|
||||
impl Default for Model {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: String::new(),
|
||||
parts: Vec::new(),
|
||||
transform: Mat4::identity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
/// Set position (translation)
|
||||
pub fn set_position(&mut self, x: f32, y: f32, z: f32) {
|
||||
self.transform = Mat4::translation(x, y, z);
|
||||
}
|
||||
|
||||
/// Set scale
|
||||
pub fn set_scale(&mut self, x: f32, y: f32, z: f32) {
|
||||
self.transform = Mat4::scale(x, y, z);
|
||||
}
|
||||
|
||||
/// Set full transform (for combining translation * rotation * scale)
|
||||
pub fn set_transform(&mut self, transform: Mat4) {
|
||||
self.transform = transform;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,3 +59,29 @@ void main() {
|
||||
vec3 result = ambient + diffuse + specular;
|
||||
frag_color = vec4(result, 1.0);
|
||||
}"#;
|
||||
|
||||
pub const VERTEX_SHADER_2D: &str = r#"
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec2 a_position;
|
||||
layout (location = 2) in vec4 a_color;
|
||||
|
||||
out vec4 v_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||
v_color = a_color;
|
||||
}
|
||||
"#;
|
||||
|
||||
pub const FRAGMENT_SHADER_2D: &str = r#"
|
||||
#version 330 core
|
||||
|
||||
in vec4 v_color;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
void main() {
|
||||
frag_color = v_color;
|
||||
}
|
||||
"#;
|
||||
|
||||
55
src/shaders/inputs.rs
Normal file
55
src/shaders/inputs.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use crate::geometry;
|
||||
|
||||
pub enum InputRequirement {
|
||||
Required,
|
||||
Optional
|
||||
}
|
||||
|
||||
pub struct ShaderInput {
|
||||
pub semantic: geometry::VertexSemantic,
|
||||
pub component_count: usize,
|
||||
pub data_type: geometry::AttributeType,
|
||||
pub requirement: InputRequirement
|
||||
}
|
||||
|
||||
pub struct ShaderInputs {
|
||||
pub inputs: Vec<ShaderInput>,
|
||||
}
|
||||
|
||||
impl ShaderInputs {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inputs: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn required(
|
||||
mut self,
|
||||
semantic: geometry::VertexSemantic,
|
||||
component_count: usize,
|
||||
data_type: geometry::AttributeType
|
||||
) -> Self {
|
||||
self.inputs.push(ShaderInput {
|
||||
semantic,
|
||||
data_type,
|
||||
component_count,
|
||||
requirement: InputRequirement::Required,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn optional(
|
||||
mut self,
|
||||
semantic: geometry::VertexSemantic,
|
||||
component_count: usize,
|
||||
data_type: geometry::AttributeType
|
||||
) -> Self {
|
||||
self.inputs.push(ShaderInput {
|
||||
semantic,
|
||||
data_type,
|
||||
component_count,
|
||||
requirement: InputRequirement::Optional,
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,19 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct ShaderSource {}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Shader(pub u32);
|
||||
|
||||
pub type ShaderHandle = u32;
|
||||
impl From<Shader> for u32 {
|
||||
fn from(value: Shader) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Shader {
|
||||
type Target = u32;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user