RustPhysicsMQ/src/rendering.rs

253 lines
8.1 KiB
Rust
Raw Normal View History

2025-11-28 20:39:09 +00:00
use crate::{
camera::{self as cam, FirstPersonCamera},
engine::World,
graphics_util::draw_cuboid,
};
use macroquad::prelude as mq;
use rapier3d::prelude::*;
const DEPTH_MAP_SIZE: u32 = 512;
const ENABLE_SHADOWS: bool = true;
const LIGHT_PROJECTION_SIZE: f32 = 20.0;
const LIGHT_NEAR: f32 = 10.0;
const LIGHT_FAR: f32 = 100.0;
pub struct Light {
projection_matrix: mq::Mat4,
view_matrix: mq::Mat4,
pub position: mq::Vec3,
pub front: mq::Vec3,
}
impl Light {
pub fn new() -> Light {
let mut l = Light {
projection_matrix: mq::Mat4::orthographic_rh(
-LIGHT_PROJECTION_SIZE,
LIGHT_PROJECTION_SIZE,
-LIGHT_PROJECTION_SIZE,
LIGHT_PROJECTION_SIZE,
LIGHT_NEAR,
LIGHT_FAR,
),
view_matrix: mq::Mat4::NAN,
position: mq::Vec3::NAN,
front: mq::Vec3::NAN,
};
l.set_location(mq::vec3(5.0, 10.0, 0.0), mq::Vec3::NEG_Y);
return l;
}
pub fn set_location(&mut self, position: mq::Vec3, front: mq::Vec3) {
self.position = position;
self.front = front;
self.view_matrix =
mq::Mat4::look_at_rh(self.position, self.position + self.front, mq::Vec3::Y);
}
pub fn get_space_matrix(&self) -> mq::Mat4 {
return self.projection_matrix * self.view_matrix;
}
}
pub struct Renderer {
base_material: mq::Material,
depth_material: mq::Material,
depth_target: mq::RenderTarget,
pub light: Light,
pub camera: cam::FirstPersonCamera,
has_light_moved: bool,
}
impl Renderer {
pub fn new() -> Renderer {
let material = mq::load_material(
mq::ShaderSource::Glsl {
vertex: include_str!("shaders/shader.vert"),
fragment: include_str!("shaders/shader.frag"),
},
mq::MaterialParams {
pipeline_params: mq::PipelineParams {
cull_face: macroquad::miniquad::CullFace::Front,
depth_test: mq::Comparison::LessOrEqual,
depth_write: true,
..Default::default()
},
uniforms: vec![
mq::UniformDesc::new("render_normals_bool", mq::UniformType::Int1),
mq::UniformDesc::new("render_shadows_bool", mq::UniformType::Int1),
mq::UniformDesc::new("light_position", mq::UniformType::Float3),
mq::UniformDesc::new("light_space_matrix", mq::UniformType::Mat4),
],
textures: vec![String::from("shadow_map")],
..Default::default()
},
)
.unwrap();
material.set_uniform("render_normals_bool", 0);
material.set_uniform("render_shadows_bool", ENABLE_SHADOWS);
let depth_material = mq::load_material(
mq::ShaderSource::Glsl {
vertex: include_str!("shaders/depth.vert"),
fragment: include_str!("shaders/depth.frag"),
},
mq::MaterialParams {
pipeline_params: mq::PipelineParams {
// cull_face: macroquad::miniquad::CullFace::Back,
depth_test: mq::Comparison::LessOrEqual,
depth_write: true,
..Default::default()
},
uniforms: vec![mq::UniformDesc::new(
"light_space_matrix",
mq::UniformType::Mat4,
)],
..Default::default()
},
)
.unwrap();
let depth_map_texture = mq::render_target_ex(
DEPTH_MAP_SIZE,
DEPTH_MAP_SIZE,
mq::RenderTargetParams {
sample_count: 1,
depth: true,
},
);
depth_map_texture
.texture
.set_filter(mq::FilterMode::Nearest);
let light = Light::new();
let camera = FirstPersonCamera::new(mq::vec3(10.0, 50.0, 10.0));
let mut r = Renderer {
base_material: material,
depth_material,
depth_target: depth_map_texture,
light,
camera,
has_light_moved: true,
};
r.light
.set_location(mq::vec3(10.0, 40.0, 10.0), mq::Vec3::NEG_Y);
r.update_light();
return r;
}
pub fn update_camera(&mut self) {
self.camera.update(mq::get_frame_time());
}
pub fn update_light(&mut self) {
let light_space_matrix = self.light.get_space_matrix();
self.base_material
.set_uniform("light_position", self.light.position);
self.base_material
.set_uniform("light_space_matrix", light_space_matrix);
self.depth_material
.set_uniform("light_space_matrix", light_space_matrix);
self.has_light_moved = true;
}
fn render_depth(&mut self, mut world: &mut World) {
mq::set_camera(&mq::Camera3D {
position: self.light.position,
target: self.light.position + self.light.front,
up: mq::Vec3::Y,
render_target: Some(self.depth_target.clone()),
..Default::default()
});
mq::gl_use_material(&self.depth_material);
mq::clear_background(mq::DARKGRAY);
draw_world(&mut world, None);
mq::gl_use_default_material();
mq::set_default_camera();
self.base_material
.set_texture("shadow_map", self.depth_target.texture.clone());
}
fn render_default(&mut self, mut world: &mut World) {
mq::clear_background(mq::LIGHTGRAY);
self.camera.apply();
draw_world(&mut world, Some(&self.base_material));
mq::draw_sphere(self.light.position, 0.25, None, mq::WHITE);
mq::draw_grid(20, 1., mq::BLACK, mq::GRAY);
mq::gl_use_default_material();
mq::set_default_camera();
}
fn render_ui(&mut self) {
mq::set_default_camera();
mq::draw_texture_ex(
&self.depth_target.texture,
0.,
0.,
mq::WHITE,
mq::DrawTextureParams {
flip_y: true,
dest_size: Some(mq::vec2(200.0, 200.0)),
..Default::default()
},
);
}
pub fn draw(&mut self, mut world: &mut World) {
if ENABLE_SHADOWS {
self.render_depth(&mut world);
self.has_light_moved = false;
}
self.render_default(&mut world);
self.render_ui();
}
}
fn draw_world(world: &mut World, material: Option<&mq::Material>) {
for (handle, coll) in world.colliders.iter() {
let position: glam::Vec3 = world.position_of_collider(handle).unwrap().into();
let rotation = *coll.rotation();
unsafe {
let context = mq::get_internal_gl().quad_gl;
context.push_model_matrix(mq::Mat4::from_rotation_translation(
rotation.into(),
position,
));
}
let color = world.collider_data.get(&handle).unwrap().color;
match coll.shape().shape_type() {
ShapeType::Ball => {
mq::draw_sphere(
mq::vec3(0.0, 0.0, 0.0),
coll.shape().as_ball().unwrap().radius,
None,
color,
);
}
ShapeType::Cuboid => {
match material {
Some(mat) => {
mq::gl_use_material(&mat);
}
None => {}
}
draw_cuboid(
mq::vec3(0.0, 0.0, 0.0),
(coll.shape().as_cuboid().unwrap().half_extents * 2.0).into(),
color,
);
match material {
Some(_) => {
mq::gl_use_default_material();
}
None => {}
}
}
_ => println!("Not implemented.. Skipping"),
}
unsafe {
let context = mq::get_internal_gl().quad_gl;
context.pop_model_matrix();
}
}
}