From 41d0819814663a87ccc8951f5a954d4ce43bf5d3 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 13:29:57 +0200 Subject: [PATCH 01/15] refactor: simplify VertexAttribPointer call and update vertex, color, index data with alpha transparency and z-depth --- src/main.rs | 50 +++++++++++++------------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/src/main.rs b/src/main.rs index 96969b3..313c584 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,14 +105,7 @@ unsafe fn create_vao(vertices: &Vec, colors: &Vec, indices: &Vec) colors.as_ptr() as *const c_void, gl::STATIC_DRAW, ); - gl::VertexAttribPointer( - 1, - 4, - gl::FLOAT, - gl::FALSE, - 0, - std::ptr::null(), - ); + gl::VertexAttribPointer(1, 4, gl::FLOAT, gl::FALSE, 0, std::ptr::null()); gl::EnableVertexAttribArray(1); vao_id @@ -189,38 +182,21 @@ fn main() { // == // Set up your VAO around here let vertices = vec![ - // triangle 1 - -0.8, -0.8, 0.0, - -0.2, -0.8, 0.0, - -0.5, -0.2, 0.0, - // triangle 2 - 0.2, -0.8, 0.0, - 0.8, -0.8, 0.0, - 0.5, -0.2, 0.0, - // triangle 3 - -0.3, 0.2, 0.0, - 0.3, 0.2, 0.0, - 0.0, 0.8, 0.0, - ]; - let indices = vec![ - 0, 1, 2, - 3, 4, 5, - 6, 7, 8, + // triangle 1 (red, z=0.5) + -0.6, -0.3, 0.5, 0.6, -0.3, 0.5, 0.0, 0.6, 0.5, // triangle 2 (green, z=0.0) + -0.3, -0.6, 0.0, 0.3, -0.6, 0.0, 0.0, 0.3, 0.0, // triangle 3 (blue, z=-0.5) + -0.4, 0.4, -0.5, 0.4, 0.4, -0.5, 0.0, -0.4, -0.5, ]; + let indices = vec![0, 1, 2, 3, 4, 5, 6, 8, 7]; let colors = vec![ - // triangle 1 colors - 1.0, 0.0, 0.0, 1.0, - 0.0, 1.0, 0.0, 1.0, - 0.0, 0.0, 1.0, 1.0, - // triangle 2 colors - 1.0, 1.0, 0.0, 1.0, - 0.0, 1.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - // triangle 3 colors - 0.5, 0.5, 0.5, 1.0, - 1.0, 0.5, 0.0, 1.0, - 0.0, 0.5, 1.0, 1.0, + // triangle 1 colors (red, α=0.5) + 1.0, 0.0, 0.0, 0.3, 1.0, 0.0, 0.0, 0.3, 1.0, 0.0, 0.0, 0.3, + // triangle 2 colors (green, α=0.5) + 0.0, 1.0, 0.0, 0.3, 0.0, 1.0, 0.0, 0.3, 0.0, 1.0, 0.0, 0.3, + // triangle 3 colors (blue, α=0.5) + 0.0, 0.0, 1.0, 0.3, 0.0, 0.0, 1.0, 0.3, 0.0, 0.0, 1.0, 0.3, ]; + let my_vao = unsafe { create_vao(&vertices, &colors, &indices) }; // == // Set up your shaders here From d3fde9cfc2182a4576bb082dbb5c55ca73d1d75f Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:32:19 +0200 Subject: [PATCH 02/15] refactor: update vertex data and add transform matrix in vertex shader --- shaders/simple.vert | 11 +++++++++- src/main.rs | 51 ++++++++++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/shaders/simple.vert b/shaders/simple.vert index 5f93d4e..2a10ade 100644 --- a/shaders/simple.vert +++ b/shaders/simple.vert @@ -4,7 +4,16 @@ in layout(location=0) vec3 position; in layout(location=1) vec4 aColor; out vec4 vColor; +mat4 transform; + void main() { - gl_Position = vec4(position, 1.0f); + transform = mat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + + gl_Position = transform * vec4(position, 1.0f); vColor = aColor; } diff --git a/src/main.rs b/src/main.rs index 313c584..7df1d18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,21 +181,42 @@ fn main() { // == // Set up your VAO around here - let vertices = vec![ - // triangle 1 (red, z=0.5) - -0.6, -0.3, 0.5, 0.6, -0.3, 0.5, 0.0, 0.6, 0.5, // triangle 2 (green, z=0.0) - -0.3, -0.6, 0.0, 0.3, -0.6, 0.0, 0.0, 0.3, 0.0, // triangle 3 (blue, z=-0.5) - -0.4, 0.4, -0.5, 0.4, 0.4, -0.5, 0.0, -0.4, -0.5, - ]; - let indices = vec![0, 1, 2, 3, 4, 5, 6, 8, 7]; - let colors = vec![ - // triangle 1 colors (red, α=0.5) - 1.0, 0.0, 0.0, 0.3, 1.0, 0.0, 0.0, 0.3, 1.0, 0.0, 0.0, 0.3, - // triangle 2 colors (green, α=0.5) - 0.0, 1.0, 0.0, 0.3, 0.0, 1.0, 0.0, 0.3, 0.0, 1.0, 0.0, 0.3, - // triangle 3 colors (blue, α=0.5) - 0.0, 0.0, 1.0, 0.3, 0.0, 0.0, 1.0, 0.3, 0.0, 0.0, 1.0, 0.3, - ]; + let vertices = vec![ + // triangle 1 + -0.8, -0.8, 0.0, + -0.2, -0.8, 0.0, + -0.5, -0.2, 0.0, + // triangle 2 + 0.2, -0.8, 0.0, + 0.8, -0.8, 0.0, + 0.5, -0.2, 0.0, + // triangle 3 + -0.3, 0.2, 0.0, + 0.3, 0.2, 0.0, + 0.0, 0.8, 0.0, + ]; + let indices = vec![ + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + ]; + let colors = vec![ + // triangle 1 colors + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0, + // triangle 2 colors + 1.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 1.0, 1.0, + // triangle 3 colors + 0.5, 0.5, 0.5, 1.0, + 1.0, 0.5, 0.0, 1.0, + 0.0, 0.5, 1.0, 1.0, + ]; + + + let my_vao = unsafe { create_vao(&vertices, &colors, &indices) }; From 0b7dad576ba1e0a9915c507182c0bff0d77c5c1b Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:39:39 +0200 Subject: [PATCH 03/15] nix --- .gitignore | 4 ++++ flake.nix | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index ce22535..5081f6a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ *.pdf *.html source.zip + +.aider* +flake.lock + diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..051f033 --- /dev/null +++ b/flake.nix @@ -0,0 +1,54 @@ +{ + description = "Rust dev shell for building project with fontconfig and OpenGL support on nixos"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + }; + + nativeBuildInputs = with pkgs; [ + git + pkg-config + fontconfig + freetype + rustup + cmake + gnumake + gcc + cargo + xorg.libXcursor + xorg.libXrandr + xorg.libXi + xorg.libX11 + xorg.libxcb + libxkbcommon + libGL + libGLU + mesa + wayland + libglibutil + ]; + + fontconfigPcPath = "${pkgs.fontconfig.dev}/lib/pkgconfig"; + in { + devShells.default = pkgs.mkShell { + name = "rust-fontconfig-shell"; + packages = nativeBuildInputs; + + shellHook = '' + export PKG_CONFIG_PATH=${fontconfigPcPath}:$PKG_CONFIG_PATH + export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath nativeBuildInputs}:$LD_LIBRARY_PATH + echo "PKG_CONFIG_PATH set to: ${fontconfigPcPath}" + echo "LD_LIBRARY_PATH set for runtime OpenGL/GUI deps" + ''; + }; + }); +} + From 70f6812fb42e7e3b4d63ab59b02d33a038f997a1 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:45:30 +0200 Subject: [PATCH 04/15] feat: add uniform transform matrix with modifiable elements in main.rs --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index 7df1d18..3e99a2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -236,6 +236,8 @@ fn main() { .attach_file("./shaders/simple.frag") .link() }; + // get uniform location for the matrix (named `transform` in your vertex shader) + let transform_loc = unsafe { simple_shader.get_uniform_location("transform") }; // Used to demonstrate keyboard handling for exercise 2. let mut _arbitrary_number = 0.0; // feel free to remove @@ -298,6 +300,11 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); + // build and send the transform matrix (start from identity) + let mut transform = glm::identity(); + // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. + transform[(0,0)] = elapsed.sin(); + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( gl::TRIANGLES, From 179da917706916f95bf1a480a6addfa820c5442d Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:46:30 +0200 Subject: [PATCH 05/15] fix: add type annotation to resolve ambiguous transform matrix type in main.rs --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3e99a2a..4c333eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -301,7 +301,7 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); // build and send the transform matrix (start from identity) - let mut transform = glm::identity(); + let mut transform: glm::Mat4 = glm::identity(); // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. transform[(0,0)] = elapsed.sin(); gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); From ff9600071f878cf8636cccad2c82cd9e36cd63f9 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:57:32 +0200 Subject: [PATCH 06/15] feat: cycle through transform matrix params a-f over time in main.rs uniform update --- src/main.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4c333eb..c592a97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -302,8 +302,19 @@ fn main() { simple_shader.activate(); // build and send the transform matrix (start from identity) let mut transform: glm::Mat4 = glm::identity(); - // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. - transform[(0,0)] = elapsed.sin(); + // cycle through each transform parameter (a,b,c,d,e,f) over time + let cycle_duration = 2.0; + let idx = ((elapsed / cycle_duration).floor() as usize) % 6; + let v = elapsed.sin(); + match idx { + 0 => transform[(0,0)] = v, // a + 1 => transform[(0,1)] = v, // b + 2 => transform[(0,3)] = v, // c + 3 => transform[(1,0)] = v, // d + 4 => transform[(1,1)] = v, // e + 5 => transform[(1,3)] = v, // f + _ => {} + } gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( From 64f04a8b4c4e34d701c6e30a81f6edef4551a49c Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 16:36:59 +0200 Subject: [PATCH 07/15] vert --- shaders/simple.vert | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/shaders/simple.vert b/shaders/simple.vert index 2a10ade..7dad78c 100644 --- a/shaders/simple.vert +++ b/shaders/simple.vert @@ -3,17 +3,9 @@ in layout(location=0) vec3 position; in layout(location=1) vec4 aColor; out vec4 vColor; - -mat4 transform; +uniform mat4 transform; void main() { - transform = mat4( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ); - gl_Position = transform * vec4(position, 1.0f); vColor = aColor; } From 0400e0969da023d098a90037d1c26f6af5ccb419 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:09:00 +0200 Subject: [PATCH 08/15] feat: bind transform uniform to location 0 in vertex shader for clarity --- shaders/simple.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaders/simple.vert b/shaders/simple.vert index 7dad78c..7eb80e9 100644 --- a/shaders/simple.vert +++ b/shaders/simple.vert @@ -3,7 +3,7 @@ in layout(location=0) vec3 position; in layout(location=1) vec4 aColor; out vec4 vColor; -uniform mat4 transform; +layout(location = 0) uniform mat4 transform; void main() { gl_Position = transform * vec4(position, 1.0f); From b08a38ce74c1cd26f06a4c5076b092e2e3e815b9 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:10:42 +0200 Subject: [PATCH 09/15] feat: apply translation and perspective projection to transform matrix before shader upload --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index c592a97..9b2b942 100644 --- a/src/main.rs +++ b/src/main.rs @@ -315,6 +315,13 @@ fn main() { 5 => transform[(1,3)] = v, // f _ => {} } + // move scene into viewable negative z range + let translation: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); + transform = translation * transform; + // apply perspective projection: (aspect, fovy radians, near, far) + let projection: glm::Mat4 = + glm::perspective(window_aspect_ratio, std::f32::consts::PI / 4.0, 1.0, 100.0); + transform = projection * transform; gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( From f6422f403e0390dfe677e9f869843900144a1dda Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:27:23 +0200 Subject: [PATCH 10/15] feat: add camera position and orientation variables for tripod motion control --- src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.rs b/src/main.rs index 9b2b942..effc9a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -242,6 +242,11 @@ fn main() { // Used to demonstrate keyboard handling for exercise 2. let mut _arbitrary_number = 0.0; // feel free to remove + // camera position (x, y, z) and orientation (yaw, pitch) + let mut cam_pos: glm::Vec3 = glm::vec3(0.0, 0.0, 0.0); + let mut cam_yaw: f32 = 0.0; + let mut cam_pitch: f32 = 0.0; + // The main rendering loop let first_frame_time = std::time::Instant::now(); let mut previous_frame_time = first_frame_time; From 861c6ebd62ae55897a7fb84cffd729c563d5eff0 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:34:34 +0200 Subject: [PATCH 11/15] feat: add key handlers for tripod camera movement and rotation controls --- src/main.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index effc9a6..4ffcb8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,19 +270,22 @@ fn main() { } } - // Handle keyboard input + // Handle keyboard input for camera movement and rotation if let Ok(keys) = pressed_keys.lock() { for key in keys.iter() { match key { - // The `VirtualKeyCode` enum is defined here: - // https://docs.rs/winit/0.25.0/winit/event/enum.VirtualKeyCode.html - VirtualKeyCode::A => { - _arbitrary_number += delta_time; - } - VirtualKeyCode::D => { - _arbitrary_number -= delta_time; - } - + // Movement: WASD + Space (up) + LShift (down) + VirtualKeyCode::W => { cam_pos.z -= delta_time; } + VirtualKeyCode::S => { cam_pos.z += delta_time; } + VirtualKeyCode::A => { cam_pos.x -= delta_time; } + VirtualKeyCode::D => { cam_pos.x += delta_time; } + VirtualKeyCode::Space => { cam_pos.y += delta_time; } + VirtualKeyCode::LShift => { cam_pos.y -= delta_time; } + // Rotation: arrow keys for yaw and pitch + VirtualKeyCode::Left => { cam_yaw -= delta_time; } + VirtualKeyCode::Right => { cam_yaw += delta_time; } + VirtualKeyCode::Up => { cam_pitch += delta_time; } + VirtualKeyCode::Down => { cam_pitch -= delta_time; } // default handler: _ => {} } From de7cc20db317bc9ee8b387f09dbe35f2527be663 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:38:35 +0200 Subject: [PATCH 12/15] fix: apply correct model, view, and projection matrices for camera motion each frame --- src/main.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4ffcb8e..0710d42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -308,28 +308,34 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); - // build and send the transform matrix (start from identity) - let mut transform: glm::Mat4 = glm::identity(); + // build Model matrix (start from identity) + let mut model: glm::Mat4 = glm::identity(); // cycle through each transform parameter (a,b,c,d,e,f) over time let cycle_duration = 2.0; let idx = ((elapsed / cycle_duration).floor() as usize) % 6; let v = elapsed.sin(); match idx { - 0 => transform[(0,0)] = v, // a - 1 => transform[(0,1)] = v, // b - 2 => transform[(0,3)] = v, // c - 3 => transform[(1,0)] = v, // d - 4 => transform[(1,1)] = v, // e - 5 => transform[(1,3)] = v, // f + 0 => model[(0,0)] = v, // a + 1 => model[(0,1)] = v, // b + 2 => model[(0,3)] = v, // c + 3 => model[(1,0)] = v, // d + 4 => model[(1,1)] = v, // e + 5 => model[(1,3)] = v, // f _ => {} } - // move scene into viewable negative z range - let translation: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); - transform = translation * transform; - // apply perspective projection: (aspect, fovy radians, near, far) + // model translation to initial view distance + let translation_model: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); + let model = translation_model * model; + // build View matrix: translate and rotate world relative to camera + let view_translation: glm::Mat4 = glm::translation(&(-cam_pos)); + let view_rot_y: glm::Mat4 = glm::rotation(-cam_yaw, &glm::vec3(0.0, 1.0, 0.0)); + let view_rot_x: glm::Mat4 = glm::rotation(-cam_pitch, &glm::vec3(1.0, 0.0, 0.0)); + let view: glm::Mat4 = view_rot_x * view_rot_y * view_translation; + // build Projection matrix let projection: glm::Mat4 = glm::perspective(window_aspect_ratio, std::f32::consts::PI / 4.0, 1.0, 100.0); - transform = projection * transform; + // final transform: Projection * View * Model + let transform: glm::Mat4 = projection * view * model; gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( From e3509a7ece35893cad1fab7c32caa8e494b3c965 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 00:15:39 +0200 Subject: [PATCH 13/15] feat: move camera relative to its orientation and clamp pitch angle --- src/main.rs | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0710d42..638ee6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -272,24 +272,36 @@ fn main() { // Handle keyboard input for camera movement and rotation if let Ok(keys) = pressed_keys.lock() { + // movement speed + let speed = 2.5 * delta_time; + // camera direction vectors based on yaw & pitch + let front = glm::vec3( + cam_yaw.sin() * cam_pitch.cos(), + cam_pitch.sin(), + -cam_yaw.cos() * cam_pitch.cos(), + ); + let right = glm::normalize(&glm::cross(&front, &glm::vec3(0.0, 1.0, 0.0))); + let up_vec = glm::normalize(&glm::cross(&right, &front)); for key in keys.iter() { match key { - // Movement: WASD + Space (up) + LShift (down) - VirtualKeyCode::W => { cam_pos.z -= delta_time; } - VirtualKeyCode::S => { cam_pos.z += delta_time; } - VirtualKeyCode::A => { cam_pos.x -= delta_time; } - VirtualKeyCode::D => { cam_pos.x += delta_time; } - VirtualKeyCode::Space => { cam_pos.y += delta_time; } - VirtualKeyCode::LShift => { cam_pos.y -= delta_time; } - // Rotation: arrow keys for yaw and pitch - VirtualKeyCode::Left => { cam_yaw -= delta_time; } - VirtualKeyCode::Right => { cam_yaw += delta_time; } - VirtualKeyCode::Up => { cam_pitch += delta_time; } - VirtualKeyCode::Down => { cam_pitch -= delta_time; } - // default handler: + // Move relative to camera orientation + VirtualKeyCode::W => { cam_pos += front * speed; } + VirtualKeyCode::S => { cam_pos -= front * speed; } + VirtualKeyCode::A => { cam_pos -= right * speed; } + VirtualKeyCode::D => { cam_pos += right * speed; } + VirtualKeyCode::Space => { cam_pos += up_vec * speed; } + VirtualKeyCode::LShift => { cam_pos -= up_vec * speed; } + // Rotation: adjust yaw and pitch + VirtualKeyCode::Left => { cam_yaw -= delta_time; } + VirtualKeyCode::Right => { cam_yaw += delta_time; } + VirtualKeyCode::Up => { cam_pitch += delta_time; } + VirtualKeyCode::Down => { cam_pitch -= delta_time; } _ => {} } } + // clamp pitch to avoid flipping + let pitch_limit = std::f32::consts::FRAC_PI_2 - 0.01; + cam_pitch = cam_pitch.clamp(-pitch_limit, pitch_limit); } // Handle mouse movement. delta contains the x and y movement of the mouse since last frame in pixels if let Ok(mut delta) = mouse_delta.lock() { From 74342b5d1adbd097a7ffa2b631b11308136fe503 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 10:47:02 +0200 Subject: [PATCH 14/15] feat: add camera-facing billboard quad rendering with rotation invariance --- src/main.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main.rs b/src/main.rs index 638ee6f..d2a8c69 100644 --- a/src/main.rs +++ b/src/main.rs @@ -220,6 +220,24 @@ fn main() { let my_vao = unsafe { create_vao(&vertices, &colors, &indices) }; + let billboard_vertices = vec![ + -0.5, -0.5, 0.0, + -0.5, 0.5, 0.0, + 0.5, 0.5, 0.0, + 0.5, -0.5, 0.0, + ]; + let billboard_indices = vec![ + 0, 1, 2, + 0, 2, 3, + ]; + let billboard_colors = vec![ + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + ]; + let billboard_vao = unsafe { create_vao(&billboard_vertices, &billboard_colors, &billboard_indices) }; + // == // Set up your shaders here // Basic usage of shader helper: @@ -356,6 +374,21 @@ fn main() { gl::UNSIGNED_INT, std::ptr::null(), ); + + // Draw billboard (camera-facing quad) + let translation_bill = glm::translation(&glm::vec3(0.0, 0.0, -2.0)); + let inv_rot_y = glm::rotation(cam_yaw, &glm::vec3(0.0, 1.0, 0.0)); + let inv_rot_x = glm::rotation(cam_pitch, &glm::vec3(1.0, 0.0, 0.0)); + let model_billboard = translation_bill * inv_rot_y * inv_rot_x; + let transform_bill = projection * view * model_billboard; + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform_bill.as_ptr()); + gl::BindVertexArray(billboard_vao); + gl::DrawElements( + gl::TRIANGLES, + billboard_indices.len() as i32, + gl::UNSIGNED_INT, + std::ptr::null(), + ); } // Display the new color buffer on the display From 5d643ddb4efa2b5eb1cd8e123ef0dd59b85eed42 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 10:53:44 +0200 Subject: [PATCH 15/15] feat: render a large grid of point-particles as billboards with program point size enabled --- src/main.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main.rs b/src/main.rs index d2a8c69..d739398 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,6 +163,7 @@ fn main() { gl::Disable(gl::MULTISAMPLE); gl::Enable(gl::BLEND); gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + gl::Enable(gl::PROGRAM_POINT_SIZE); gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); gl::DebugMessageCallback(Some(util::debug_callback), ptr::null()); @@ -238,6 +239,22 @@ fn main() { ]; let billboard_vao = unsafe { create_vao(&billboard_vertices, &billboard_colors, &billboard_indices) }; + // Generate a grid of point‐particles + let grid_size = 200; + let mut particle_vertices = Vec::with_capacity(grid_size * grid_size * 3); + let mut particle_colors = Vec::with_capacity(grid_size * grid_size * 4); + for i in 0..grid_size { + for j in 0..grid_size { + let x = (i as f32 / grid_size as f32 - 0.5) * 20.0; + let y = (j as f32 / grid_size as f32 - 0.5) * 20.0; + let z = -5.0; + particle_vertices.extend_from_slice(&[x, y, z]); + particle_colors.extend_from_slice(&[1.0, 1.0, 1.0, 1.0]); + } + } + let particle_vao = unsafe { create_vao(&particle_vertices, &particle_colors, &Vec::new()) }; + let particle_count = (grid_size * grid_size) as i32; + // == // Set up your shaders here // Basic usage of shader helper: @@ -375,6 +392,12 @@ fn main() { std::ptr::null(), ); + // Draw point‐particles + let transform_particles = projection * view * glm::identity(); + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform_particles.as_ptr()); + gl::BindVertexArray(particle_vao); + gl::DrawArrays(gl::POINTS, 0, particle_count); + // Draw billboard (camera-facing quad) let translation_bill = glm::translation(&glm::vec3(0.0, 0.0, -2.0)); let inv_rot_y = glm::rotation(cam_yaw, &glm::vec3(0.0, 1.0, 0.0));