summaryrefslogtreecommitdiff
path: root/engine/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-11-12 22:38:52 +0100
committerHampusM <hampus@hampusmat.com>2023-11-12 22:57:19 +0100
commit8d821588cd4f51d4ae9c4ef52d45c0af0e1ce9e5 (patch)
treeed1b0dd30e801b9a70537b9806a445e4212978b3 /engine/src
parent67023d6a095f457a2579367d59d13c6c804e7108 (diff)
feat(engine): add basic flat lighting
Diffstat (limited to 'engine/src')
-rw-r--r--engine/src/color.rs5
-rw-r--r--engine/src/lib.rs46
-rw-r--r--engine/src/lighting.rs93
-rw-r--r--engine/src/math.rs17
-rw-r--r--engine/src/opengl/shader.rs36
-rw-r--r--engine/src/renderer/mod.rs65
-rw-r--r--engine/src/vector.rs22
-rw-r--r--engine/src/vertex.rs20
8 files changed, 301 insertions, 3 deletions
diff --git a/engine/src/color.rs b/engine/src/color.rs
index 1e87cb9..2fd2cd3 100644
--- a/engine/src/color.rs
+++ b/engine/src/color.rs
@@ -6,3 +6,8 @@ pub struct Color<Value>
pub green: Value,
pub blue: Value,
}
+
+impl Color<f32>
+{
+ pub const WHITE_F32: Self = Self { red: 1.0, green: 1.0, blue: 1.0 };
+}
diff --git a/engine/src/lib.rs b/engine/src/lib.rs
index 0eca914..e6568a1 100644
--- a/engine/src/lib.rs
+++ b/engine/src/lib.rs
@@ -7,6 +7,7 @@ use glfw::window::KeyState;
use glfw::{Window, WindowBuilder};
use crate::camera::Camera;
+use crate::lighting::{LightSettings, LightSource};
use crate::object::{Id as ObjectId, Object};
use crate::renderer::Renderer;
use crate::vector::Vec2;
@@ -20,6 +21,8 @@ mod transform;
pub mod camera;
pub mod color;
+pub mod lighting;
+pub mod math;
pub mod object;
pub mod texture;
pub mod vector;
@@ -33,6 +36,8 @@ pub struct Engine
{
/// Objects have to be dropped before window. Otherwise, UB.
objects: BTreeMap<ObjectId, Object>,
+ light_source: Option<LightSource>,
+ light_settings: Option<LightSettings>,
window: Window,
renderer: Renderer,
delta_time: Duration,
@@ -70,6 +75,8 @@ impl Engine
window,
renderer,
objects: BTreeMap::new(),
+ light_source: None,
+ light_settings: None,
delta_time: Duration::ZERO,
})
}
@@ -85,6 +92,23 @@ impl Engine
.extend(objects.into_iter().map(|object| (object.id(), object)));
}
+ pub fn set_light_source(&mut self, light_source: LightSource)
+ {
+ self.light_source = Some(light_source);
+ }
+
+ #[must_use]
+ pub fn light_source(&self) -> Option<&LightSource>
+ {
+ self.light_source.as_ref()
+ }
+
+ #[must_use]
+ pub fn light_source_mut(&mut self) -> Option<&mut LightSource>
+ {
+ self.light_source.as_mut()
+ }
+
#[must_use]
pub fn get_object_by_id(&self, id: ObjectId) -> Option<&Object>
{
@@ -105,6 +129,8 @@ impl Engine
{
let mut prev_frame_start: Option<Instant> = None;
+ let default_light_settings = LightSettings::default();
+
while !self.window.should_close() {
self.update_delta_time(&mut prev_frame_start);
@@ -112,7 +138,14 @@ impl Engine
let window_size = self.window.size().map_err(Error::GetWindowSizeFailed)?;
- self.renderer.render(self.objects.values(), &window_size);
+ self.renderer.render(
+ self.objects.values(),
+ self.light_source.as_ref(),
+ self.light_settings
+ .as_ref()
+ .unwrap_or(&default_light_settings),
+ &window_size,
+ );
self.window
.swap_buffers()
@@ -171,6 +204,17 @@ impl Engine
Ok(Vec2 { x: pos.x, y: pos.y })
}
+ pub fn set_light_settings(&mut self, light_settings: LightSettings)
+ {
+ self.light_settings = Some(light_settings);
+ }
+
+ #[must_use]
+ pub fn light_settings(&self) -> Option<&LightSettings>
+ {
+ self.light_settings.as_ref()
+ }
+
fn update_delta_time(&mut self, prev_frame_start: &mut Option<Instant>)
{
let frame_start_time = Instant::now();
diff --git a/engine/src/lighting.rs b/engine/src/lighting.rs
new file mode 100644
index 0000000..e7fb901
--- /dev/null
+++ b/engine/src/lighting.rs
@@ -0,0 +1,93 @@
+use crate::color::Color;
+use crate::vector::Vec3;
+
+#[derive(Debug, Clone)]
+pub struct LightSettings
+{
+ pub ambient_light_strength: f32,
+ pub specular_light_strength: f32,
+ pub specular_shininess: u32,
+}
+
+impl Default for LightSettings
+{
+ fn default() -> Self
+ {
+ Self {
+ ambient_light_strength: 1.0,
+ specular_light_strength: 0.0,
+ specular_shininess: 32,
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct LightSource
+{
+ position: Vec3<f32>,
+ color: Color<f32>,
+}
+
+impl LightSource
+{
+ #[must_use]
+ pub fn position(&self) -> &Vec3<f32>
+ {
+ &self.position
+ }
+
+ #[must_use]
+ pub fn color(&self) -> &Color<f32>
+ {
+ &self.color
+ }
+
+ pub fn translate(&mut self, translation: Vec3<f32>)
+ {
+ self.position += translation;
+ }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct LightSourceBuilder
+{
+ position: Vec3<f32>,
+ color: Color<f32>,
+}
+
+impl LightSourceBuilder
+{
+ #[must_use]
+ pub fn new() -> Self
+ {
+ Self {
+ position: Vec3::default(),
+ color: Color::WHITE_F32,
+ }
+ }
+
+ #[must_use]
+ pub fn position(mut self, position: Vec3<f32>) -> Self
+ {
+ self.position = position;
+
+ self
+ }
+
+ #[must_use]
+ pub fn color(mut self, color: Color<f32>) -> Self
+ {
+ self.color = color;
+
+ self
+ }
+
+ #[must_use]
+ pub fn build(&self) -> LightSource
+ {
+ LightSource {
+ position: self.position.clone(),
+ color: self.color.clone(),
+ }
+ }
+}
diff --git a/engine/src/math.rs b/engine/src/math.rs
new file mode 100644
index 0000000..bda3b59
--- /dev/null
+++ b/engine/src/math.rs
@@ -0,0 +1,17 @@
+//! Miscellaneous math functions.
+
+use crate::vector::Vec3;
+
+/// Calculates the surface normal of a triangle.
+#[must_use]
+pub fn calc_triangle_surface_normal(
+ egde_a: &Vec3<f32>,
+ edge_b: &Vec3<f32>,
+ edge_c: &Vec3<f32>,
+) -> Vec3<f32>
+{
+ let v1 = edge_b.clone() - egde_a.clone();
+ let v2 = edge_c.clone() - egde_a.clone();
+
+ v1.cross(&v2)
+}
diff --git a/engine/src/opengl/shader.rs b/engine/src/opengl/shader.rs
index 3dc308e..4bf56aa 100644
--- a/engine/src/opengl/shader.rs
+++ b/engine/src/opengl/shader.rs
@@ -3,6 +3,7 @@ use std::ptr::null_mut;
use crate::matrix::Matrix;
use crate::opengl::currently_bound::CurrentlyBound;
+use crate::vector::Vec3;
#[derive(Debug)]
pub struct Shader
@@ -179,6 +180,41 @@ impl Program
}
}
+ pub fn set_uniform_vec_3fv(
+ &self,
+ _: &CurrentlyBound<Self>,
+ name: &CStr,
+ vec: &Vec3<f32>,
+ )
+ {
+ let uniform_location =
+ unsafe { gl::GetUniformLocation(self.program, name.as_ptr().cast()) };
+
+ unsafe {
+ gl::Uniform3fv(uniform_location, 1, vec.as_ptr());
+ }
+ }
+
+ pub fn set_uniform_1fv(&self, _: &CurrentlyBound<Self>, name: &CStr, num: f32)
+ {
+ let uniform_location =
+ unsafe { gl::GetUniformLocation(self.program, name.as_ptr().cast()) };
+
+ unsafe {
+ gl::Uniform1fv(uniform_location, 1, &num);
+ }
+ }
+
+ pub fn set_uniform_1uiv(&self, _: &CurrentlyBound<Self>, name: &CStr, num: u32)
+ {
+ let uniform_location =
+ unsafe { gl::GetUniformLocation(self.program, name.as_ptr().cast()) };
+
+ unsafe {
+ gl::Uniform1uiv(uniform_location, 1, &num);
+ }
+ }
+
fn get_info_log(&self) -> String
{
let mut buf = vec![gl::types::GLchar::default(); 512];
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs
index 7d5e104..d46612f 100644
--- a/engine/src/renderer/mod.rs
+++ b/engine/src/renderer/mod.rs
@@ -5,6 +5,8 @@ use cstr::cstr;
use glfw::WindowSize;
use crate::camera::Camera;
+use crate::color::Color;
+use crate::lighting::{LightSettings, LightSource};
use crate::object::Object;
use crate::opengl::buffer::{
ArrayKind as ArrayBufferKind,
@@ -19,7 +21,7 @@ use crate::opengl::shader::Program as ShaderProgram;
use crate::opengl::vertex_array::{PrimitiveKind, VertexArray};
use crate::opengl::{clear_buffers, enable, BufferClearMask, Capability};
use crate::projection::new_perspective;
-use crate::vector::Vec2;
+use crate::vector::{Vec2, Vec3};
use crate::vertex::Vertex;
#[derive(Debug)]
@@ -65,6 +67,8 @@ impl Renderer
pub fn render<'obj>(
&self,
objects: impl IntoIterator<Item = &'obj Object>,
+ light_source: Option<&LightSource>,
+ light_settings: &LightSettings,
window_size: &WindowSize,
)
{
@@ -81,6 +85,14 @@ impl Renderer
&shader_program_curr_bound,
);
+ apply_light(
+ obj,
+ light_source,
+ &self.camera,
+ &shader_program_curr_bound,
+ light_settings,
+ );
+
if let Some(texture) = obj.texture() {
texture.inner().bind(|_| {
Self::draw_object(obj);
@@ -245,6 +257,57 @@ fn apply_transformation_matrices(
);
}
+fn apply_light(
+ obj: &Object,
+ light_source: Option<&LightSource>,
+ camera: &Camera,
+ shader_program_curr_bound: &CurrentlyBound<ShaderProgram>,
+ light_settings: &LightSettings,
+)
+{
+ obj.renderable().shader_program.set_uniform_vec_3fv(
+ shader_program_curr_bound,
+ cstr!("light_color"),
+ &light_source
+ .map_or(Color::WHITE_F32, |light_source| {
+ light_source.color().clone()
+ })
+ .into(),
+ );
+
+ obj.renderable().shader_program.set_uniform_vec_3fv(
+ shader_program_curr_bound,
+ cstr!("light_pos"),
+ &light_source.map_or_else(Vec3::default, |light_source| {
+ light_source.position().clone()
+ }),
+ );
+
+ obj.renderable().shader_program.set_uniform_1fv(
+ shader_program_curr_bound,
+ cstr!("ambient_light_strength"),
+ light_settings.ambient_light_strength,
+ );
+
+ obj.renderable().shader_program.set_uniform_1fv(
+ shader_program_curr_bound,
+ cstr!("specular_light_strength"),
+ light_settings.specular_light_strength,
+ );
+
+ obj.renderable().shader_program.set_uniform_1uiv(
+ shader_program_curr_bound,
+ cstr!("specular_shininess"),
+ light_settings.specular_shininess,
+ );
+
+ obj.renderable().shader_program.set_uniform_vec_3fv(
+ shader_program_curr_bound,
+ cstr!("view_pos"),
+ camera.position(),
+ );
+}
+
#[cfg(feature = "debug")]
#[tracing::instrument(skip_all)]
fn opengl_debug_message_cb(
diff --git a/engine/src/vector.rs b/engine/src/vector.rs
index 00d6a6f..a5ef911 100644
--- a/engine/src/vector.rs
+++ b/engine/src/vector.rs
@@ -1,5 +1,7 @@
use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
+use crate::color::Color;
+
#[derive(Debug, Default, Clone)]
pub struct Vec2<Value>
{
@@ -64,6 +66,14 @@ impl Vec3<f32>
}
}
+impl<Value> Vec3<Value>
+{
+ pub fn as_ptr(&self) -> *const Value
+ {
+ &self.x
+ }
+}
+
impl<Value> Sub for Vec3<Value>
where
Value: Sub<Value, Output = Value>,
@@ -215,3 +225,15 @@ where
self.z -= rhs.z;
}
}
+
+impl<Value> From<Color<Value>> for Vec3<Value>
+{
+ fn from(color: Color<Value>) -> Self
+ {
+ Self {
+ x: color.red,
+ y: color.green,
+ z: color.blue,
+ }
+ }
+}
diff --git a/engine/src/vertex.rs b/engine/src/vertex.rs
index 9df646f..bb0e890 100644
--- a/engine/src/vertex.rs
+++ b/engine/src/vertex.rs
@@ -10,6 +10,7 @@ pub struct Vertex
pos: Vec3<f32>,
color: Color<f32>,
texture_coords: Vec2<f32>,
+ normal: Vec3<f32>,
}
#[derive(Debug, Default)]
@@ -18,6 +19,7 @@ pub struct Builder
pos: Option<Vec3<f32>>,
color: Option<Color<f32>>,
texture_coords: Vec2<f32>,
+ normal: Option<Vec3<f32>>,
}
impl Builder
@@ -53,15 +55,25 @@ impl Builder
}
#[must_use]
+ pub fn normal(mut self, normal: Vec3<f32>) -> Self
+ {
+ self.normal = Some(normal);
+
+ self
+ }
+
+ #[must_use]
pub fn build(self) -> Option<Vertex>
{
let pos = self.pos?;
- let color = self.color?;
+ let color = self.color.unwrap_or_default();
+ let normal = self.normal.unwrap_or_default();
Some(Vertex {
pos,
color,
texture_coords: self.texture_coords,
+ normal,
})
}
}
@@ -89,6 +101,12 @@ impl Vertex
component_cnt: AttributeComponentCnt::Two,
component_size: size_of::<f32>(),
},
+ Attribute {
+ index: 3,
+ component_type: AttributeComponentType::Float,
+ component_cnt: AttributeComponentCnt::Three,
+ component_size: size_of::<f32>(),
+ },
]
}
}