From 7b0edcfc6a07ff4d64e602f2b68d93fedc8b826d Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 2 Aug 2026 16:11:30 +0200 Subject: fix(engine): improve portability by making matrices row-major --- engine/src/data_types/matrix.rs | 243 ++++++++++++++++++--------------- engine/src/projection.rs | 32 +++-- engine/src/rendering/backend/opengl.rs | 37 ++--- engine/src/rendering/shader.rs | 5 +- 4 files changed, 171 insertions(+), 146 deletions(-) (limited to 'engine/src') diff --git a/engine/src/data_types/matrix.rs b/engine/src/data_types/matrix.rs index cc43e7b..48796bf 100644 --- a/engine/src/data_types/matrix.rs +++ b/engine/src/data_types/matrix.rs @@ -1,12 +1,11 @@ -use std::ops::Mul; +use std::ops::{Index, IndexMut, Mul}; use crate::vector::{Vec3, Vec4}; #[derive(Debug, Clone)] pub struct Matrix { - /// Items must be layed out this way for it to work with OpenGL shaders. - pub items: [[Value; ROWS]; COLUMNS], + items: [[Value; COLUMNS]; ROWS], } impl Matrix @@ -25,21 +24,32 @@ impl Matrix(columns: [Column; COLUMNS]) -> Self where Column: Into<[Value; ROWS]>, + Value: Default, { - Self { - items: columns.map(|column| column.into()), + let mut items = + std::array::from_fn(|_| std::array::from_fn(|_| Value::default())); + + for (column_index, column) in columns.into_iter().enumerate() { + for (row_index, item) in column.into().into_iter().enumerate() { + items[row_index][column_index] = item; + } } + + Self { items } } - /// Sets the value at the specified cell. - pub fn set_cell(&mut self, row: usize, column: usize, value: Value) + pub fn get_column_copied(&self, column_index: usize) -> [Value; ROWS] + where + Value: Default + Copy, { - self.items[column][row] = value; + std::array::from_fn::(|row_index| { + self[CellPos { row: row_index, col: column_index }] + }) } - pub fn items(&self) -> &[[Value; ROWS]; COLUMNS] + pub fn items(&self) -> &[Value] { - &self.items + &self.items.as_flattened() } } @@ -60,19 +70,13 @@ impl Matrix #[must_use] pub fn new_identity() -> Self { - let mut index = 0; - - let items = [(); ROWS_COLS].map(|()| { - let mut columns = [0.0; ROWS_COLS]; + let mut identity = Self::new(); - columns[index] = 1.0; - - index += 1; - - columns - }); + for index in 0..ROWS_COLS { + identity[CellPos { row: index, col: index }] = 1.0; + } - Self { items } + identity } } @@ -80,18 +84,18 @@ impl Matrix { pub fn translate(&mut self, translation: &Vec3) { - self.set_cell(0, 3, translation.x); - self.set_cell(1, 3, translation.y); - self.set_cell(2, 3, translation.z); - self.set_cell(3, 3, 1.0); + self[CellPos { row: 0, col: 3 }] = translation.x; + self[CellPos { row: 1, col: 3 }] = translation.y; + self[CellPos { row: 2, col: 3 }] = translation.z; + self[CellPos { row: 3, col: 3 }] = 1.0; } pub fn scale(&mut self, scaling: &Vec3) { - self.set_cell(0, 0, scaling.x); - self.set_cell(1, 1, scaling.y); - self.set_cell(2, 2, scaling.z); - self.set_cell(3, 3, 1.0); + self[CellPos { row: 0, col: 0 }] = scaling.x; + self[CellPos { row: 1, col: 1 }] = scaling.y; + self[CellPos { row: 2, col: 2 }] = scaling.z; + self[CellPos { row: 3, col: 3 }] = 1.0; } pub fn look_at(&mut self, eye: Vec3, target: Vec3, up: Vec3) @@ -102,17 +106,17 @@ impl Matrix let camera_up = rev_target_direction.cross(&camera_right); - self.set_cell(0, 0, camera_right.x); - self.set_cell(0, 1, camera_right.y); - self.set_cell(0, 2, camera_right.z); + self[CellPos { row: 0, col: 0 }] = camera_right.x; + self[CellPos { row: 0, col: 1 }] = camera_right.y; + self[CellPos { row: 0, col: 2 }] = camera_right.z; - self.set_cell(1, 0, camera_up.x); - self.set_cell(1, 1, camera_up.y); - self.set_cell(1, 2, camera_up.z); + self[CellPos { row: 1, col: 0 }] = camera_up.x; + self[CellPos { row: 1, col: 1 }] = camera_up.y; + self[CellPos { row: 1, col: 2 }] = camera_up.z; - self.set_cell(2, 0, rev_target_direction.x); - self.set_cell(2, 1, rev_target_direction.y); - self.set_cell(2, 2, rev_target_direction.z); + self[CellPos { row: 2, col: 0 }] = rev_target_direction.x; + self[CellPos { row: 2, col: 1 }] = rev_target_direction.y; + self[CellPos { row: 2, col: 2 }] = rev_target_direction.z; // The vector is negated since we want the world to be translated in the opposite // direction of where we want the camera to move. @@ -122,56 +126,56 @@ impl Matrix z: rev_target_direction.dot(&eye), }; - self.set_cell(0, 3, camera_pos.x); - self.set_cell(1, 3, camera_pos.y); - self.set_cell(2, 3, camera_pos.z); + self[CellPos { row: 0, col: 3 }] = camera_pos.x; + self[CellPos { row: 1, col: 3 }] = camera_pos.y; + self[CellPos { row: 2, col: 3 }] = camera_pos.z; - self.set_cell(3, 3, 1.0); + self[CellPos { row: 3, col: 3 }] = 1.0; } pub fn inverse(&self) -> Self { - let coef_00 = - self.items[2][2] * self.items[3][3] - self.items[3][2] * self.items[2][3]; - let coef_02 = - self.items[1][2] * self.items[3][3] - self.items[3][2] * self.items[1][3]; - let coef_03 = - self.items[1][2] * self.items[2][3] - self.items[2][2] * self.items[1][3]; - - let coef_04 = - self.items[2][1] * self.items[3][3] - self.items[3][1] * self.items[2][3]; - let coef_06 = - self.items[1][1] * self.items[3][3] - self.items[3][1] * self.items[1][3]; - let coef_07 = - self.items[1][1] * self.items[2][3] - self.items[2][1] * self.items[1][3]; - - let coef_08 = - self.items[2][1] * self.items[3][2] - self.items[3][1] * self.items[2][2]; - let coef_10 = - self.items[1][1] * self.items[3][2] - self.items[3][1] * self.items[1][2]; - let coef_11 = - self.items[1][1] * self.items[2][2] - self.items[2][1] * self.items[1][2]; - - let coef_12 = - self.items[2][0] * self.items[3][3] - self.items[3][0] * self.items[2][3]; - let coef_14 = - self.items[1][0] * self.items[3][3] - self.items[3][0] * self.items[1][3]; - let coef_15 = - self.items[1][0] * self.items[2][3] - self.items[2][0] * self.items[1][3]; - - let coef_16 = - self.items[2][0] * self.items[3][2] - self.items[3][0] * self.items[2][2]; - let coef_18 = - self.items[1][0] * self.items[3][2] - self.items[3][0] * self.items[1][2]; - let coef_19 = - self.items[1][0] * self.items[2][2] - self.items[2][0] * self.items[1][2]; - - let coef_20 = - self.items[2][0] * self.items[3][1] - self.items[3][0] * self.items[2][1]; - let coef_22 = - self.items[1][0] * self.items[3][1] - self.items[3][0] * self.items[1][1]; - let coef_23 = - self.items[1][0] * self.items[2][1] - self.items[2][0] * self.items[1][1]; + let coef_00 = self[CellPos { row: 2, col: 2 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 2, col: 3 }] * self[CellPos { row: 3, col: 2 }]; + let coef_02 = self[CellPos { row: 2, col: 1 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 2, col: 3 }] * self[CellPos { row: 3, col: 1 }]; + let coef_03 = self[CellPos { row: 2, col: 1 }] * self[CellPos { row: 3, col: 2 }] + - self[CellPos { row: 2, col: 2 }] * self[CellPos { row: 3, col: 1 }]; + + let coef_04 = self[CellPos { row: 1, col: 2 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 1, col: 3 }] * self[CellPos { row: 3, col: 2 }]; + let coef_06 = self[CellPos { row: 1, col: 1 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 1, col: 3 }] * self[CellPos { row: 3, col: 1 }]; + let coef_07 = self[CellPos { row: 1, col: 1 }] * self[CellPos { row: 3, col: 2 }] + - self[CellPos { row: 1, col: 2 }] * self[CellPos { row: 3, col: 1 }]; + + let coef_08 = self[CellPos { row: 1, col: 2 }] * self[CellPos { row: 2, col: 3 }] + - self[CellPos { row: 1, col: 3 }] * self[CellPos { row: 2, col: 2 }]; + let coef_10 = self[CellPos { row: 1, col: 1 }] * self[CellPos { row: 2, col: 3 }] + - self[CellPos { row: 1, col: 3 }] * self[CellPos { row: 2, col: 1 }]; + let coef_11 = self[CellPos { row: 1, col: 1 }] * self[CellPos { row: 2, col: 2 }] + - self[CellPos { row: 1, col: 2 }] * self[CellPos { row: 2, col: 1 }]; + + let coef_12 = self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 3, col: 2 }]; + let coef_14 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 3, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 3, col: 1 }]; + let coef_15 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 3, col: 2 }] + - self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 3, col: 1 }]; + + let coef_16 = self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 2, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 2, col: 2 }]; + let coef_18 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 2, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 2, col: 1 }]; + let coef_19 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 2, col: 2 }] + - self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 2, col: 1 }]; + + let coef_20 = self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 1, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 1, col: 2 }]; + let coef_22 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 1, col: 3 }] + - self[CellPos { row: 0, col: 3 }] * self[CellPos { row: 1, col: 1 }]; + let coef_23 = self[CellPos { row: 0, col: 1 }] * self[CellPos { row: 1, col: 2 }] + - self[CellPos { row: 0, col: 2 }] * self[CellPos { row: 1, col: 1 }]; let fac_0 = Vec4 { x: coef_00, @@ -211,28 +215,28 @@ impl Matrix }; let vec_0 = Vec4 { - x: self.items[1][0], - y: self.items[0][0], - z: self.items[0][0], - w: self.items[0][0], + x: self[CellPos { row: 0, col: 1 }], + y: self[CellPos { row: 0, col: 0 }], + z: self[CellPos { row: 0, col: 0 }], + w: self[CellPos { row: 0, col: 0 }], }; let vec_1 = Vec4 { - x: self.items[1][1], - y: self.items[0][1], - z: self.items[0][1], - w: self.items[0][1], + x: self[CellPos { row: 1, col: 1 }], + y: self[CellPos { row: 1, col: 0 }], + z: self[CellPos { row: 1, col: 0 }], + w: self[CellPos { row: 1, col: 0 }], }; let vec_2 = Vec4 { - x: self.items[1][2], - y: self.items[0][2], - z: self.items[0][2], - w: self.items[0][2], + x: self[CellPos { row: 2, col: 1 }], + y: self[CellPos { row: 2, col: 0 }], + z: self[CellPos { row: 2, col: 0 }], + w: self[CellPos { row: 2, col: 0 }], }; let vec_3 = Vec4 { - x: self.items[1][3], - y: self.items[0][3], - z: self.items[0][3], - w: self.items[0][3], + x: self[CellPos { row: 3, col: 1 }], + y: self[CellPos { row: 3, col: 0 }], + z: self[CellPos { row: 3, col: 0 }], + w: self[CellPos { row: 3, col: 0 }], }; let inv_0 = vec_1 * fac_0 - vec_2 * fac_1 + vec_3 * fac_2; @@ -251,13 +255,13 @@ impl Matrix ]); let row_0 = Vec4 { - x: inverse.items[0][0], - y: inverse.items[1][0], - z: inverse.items[2][0], - w: inverse.items[3][0], + x: inverse[CellPos { row: 0, col: 0 }], + y: inverse[CellPos { row: 0, col: 1 }], + z: inverse[CellPos { row: 0, col: 2 }], + w: inverse[CellPos { row: 0, col: 3 }], }; - let dot_0 = Vec4::::from(self.items[0]) * row_0; + let dot_0 = Vec4::::from(self.get_column_copied(0)) * row_0; let dot_1 = (dot_0.x + dot_0.y) + (dot_0.z + dot_0.w); @@ -274,9 +278,34 @@ impl Mul for Matrix fn mul(self, scalar: f32) -> Self::Output { Self { - items: self - .items - .map(|column| (Vec4::from(column) * scalar).into()), + items: self.items.map(|row| (Vec4::from(row) * scalar).into()), } } } + +impl Index + for Matrix +{ + type Output = Value; + + fn index(&self, cell_pos: CellPos) -> &Self::Output + { + &self.items[cell_pos.row][cell_pos.col] + } +} + +impl IndexMut + for Matrix +{ + fn index_mut(&mut self, cell_pos: CellPos) -> &mut Self::Output + { + &mut self.items[cell_pos.row][cell_pos.col] + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CellPos +{ + pub row: usize, + pub col: usize, +} diff --git a/engine/src/projection.rs b/engine/src/projection.rs index ea3d7ed..747b8a8 100644 --- a/engine/src/projection.rs +++ b/engine/src/projection.rs @@ -1,6 +1,6 @@ use crate::builder; use crate::data_types::dimens::Dimens; -use crate::matrix::Matrix; +use crate::matrix::{CellPos as MatrixCellPos, Matrix}; use crate::reflection::Reflection; use crate::vector::Vec2; @@ -32,11 +32,15 @@ impl Perspective match clip_volume { ClipVolume::NegOneToOne => { - out.set_cell(0, 0, (1.0 / (self.fov_radians / 2.0).tan()) / aspect); - out.set_cell(1, 1, 1.0 / (self.fov_radians / 2.0).tan()); - out.set_cell(2, 2, (self.near + self.far) / (self.near - self.far)); - out.set_cell(2, 3, (2.0 * self.near * self.far) / (self.near - self.far)); - out.set_cell(3, 2, -1.0); + out[MatrixCellPos { row: 0, col: 0 }] = + (1.0 / (self.fov_radians / 2.0).tan()) / aspect; + out[MatrixCellPos { row: 1, col: 1 }] = + 1.0 / (self.fov_radians / 2.0).tan(); + out[MatrixCellPos { row: 2, col: 2 }] = + (self.near + self.far) / (self.near - self.far); + out[MatrixCellPos { row: 2, col: 3 }] = + (2.0 * self.near * self.far) / (self.near - self.far); + out[MatrixCellPos { row: 3, col: 2 }] = -1.0; } } @@ -113,13 +117,15 @@ impl Orthographic match clip_volume { ClipVolume::NegOneToOne => { - result.set_cell(0, 0, 2.0 / (right - left)); - result.set_cell(1, 1, 2.0 / (top - bottom)); - result.set_cell(2, 2, -2.0 / (far - near)); - result.set_cell(0, 3, -(right + left) / (right - left)); - result.set_cell(1, 3, -(top + bottom) / (top - bottom)); - result.set_cell(2, 3, -(far + near) / (far - near)); - result.set_cell(3, 3, 1.0); + result[MatrixCellPos { row: 0, col: 0 }] = 2.0 / (right - left); + result[MatrixCellPos { row: 1, col: 1 }] = 2.0 / (top - bottom); + result[MatrixCellPos { row: 2, col: 2 }] = -2.0 / (far - near); + result[MatrixCellPos { row: 0, col: 3 }] = + -(right + left) / (right - left); + result[MatrixCellPos { row: 1, col: 3 }] = + -(top + bottom) / (top - bottom); + result[MatrixCellPos { row: 2, col: 3 }] = -(far + near) / (far - near); + result[MatrixCellPos { row: 3, col: 3 }] = 1.0; } } diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 1253c7b..f88fe38 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -76,7 +76,6 @@ use crate::ecs::query::term::Without; use crate::ecs::sole::Single; use crate::ecs::{Component, Query, Sole}; use crate::image::{ColorType as ImageColorType, Image}; -use crate::matrix::Matrix; use crate::reflection::EnumReflectionExt; use crate::rendering::backend::opengl::glutin_compat::{ DisplayBuilder, @@ -187,16 +186,14 @@ impl crate::ecs::extension::Extension for Extension } fn prepare_windows( - window_query: Query< - ( - Option<&Window>, - &mut WindowCreationAttributes, - With, - Without, - Without, - Without, - ), - >, + window_query: Query<( + Option<&Window>, + &mut WindowCreationAttributes, + With, + Without, + Without, + Without, + )>, windowing_context: Single, graphics_props: Single, mut actions: Actions, @@ -272,9 +269,12 @@ fn prepare_windows( #[tracing::instrument(skip_all)] fn init_window_graphics( - window_query: Query< - (&Window, &WindowGlConfig, With, Without), - >, + window_query: Query<( + &Window, + &WindowGlConfig, + With, + Without, + )>, windowing_context: Single, graphics_props: Single, mut graphics_ctx: Single, @@ -1485,15 +1485,6 @@ impl From> } } -impl From> - for opengl_bindings::data_types::Matrix -{ - fn from(matrix: Matrix) -> Self - { - Self { items: matrix.items } - } -} - impl From> for opengl_bindings::data_types::Dimens { fn from(dimens: Dimens) -> Self diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs index 7d5bd51..b508670 100644 --- a/engine/src/rendering/shader.rs +++ b/engine/src/rendering/shader.rs @@ -28,12 +28,11 @@ use crate::asset::{ Submitter as AssetSubmitter, HANDLE_ASSETS_PHASE, }; -use crate::ecs::pair; use crate::builder; use crate::ecs::pair::ChildOf; use crate::ecs::phase::{Phase, POST_UPDATE as POST_UPDATE_PHASE}; use crate::ecs::sole::Single; -use crate::ecs::{declare_entity, Component, Sole}; +use crate::ecs::{declare_entity, pair, Component, Sole}; pub mod cursor; pub mod default; @@ -1018,7 +1017,7 @@ pub(super) fn prepare(collector: &mut crate::ecs::extension::Collector<'_>) let session_options = shader_slang::CompilerOptions::default() .optimization(shader_slang::OptimizationLevel::None) - .matrix_layout_column(true) + .matrix_layout_row(true) .debug_information(SlangDebugInfoLevel::Maximal) .no_mangle(true); -- cgit v1.2.3-18-g5258