1+ /*
2+ * Matrix4.cs
3+ *
4+ * Represents a 4x4 matrix with float components for 3D transformations.
5+ * Designed for graphics, raytracing, and general linear algebra operations.
6+ *
7+ * Features:
8+ * - Operator overloads for matrix addition (+), subtraction (-), and multiplication (*)
9+ * - Scalar multiplication and matrix-vector multiplication
10+ * - Mutable operations via MultiplyThisBy for in-place updates
11+ * - "Load" methods (LoadIdentity, LoadZero, LoadTranslate, LoadScale, LoadRotate)
12+ * that initialize matrices via out parameters
13+ * - Indexer for convenient element access: matrix[i, j]
14+ *
15+ * Usage:
16+ * Matrix4.LoadIdentity(out var m); // loads identity matrix
17+ * Matrix4.LoadTranslate(1, 2, 3, out var t); // translation matrix
18+ * var combined = m * t; // combine transforms
19+ * var vTransformed = combined.Multiply(vector); // transform a Vector3D
20+ *
21+ * Author: Dan Munteanu
22+ * Date: 28-Sep-2025
23+ */
24+
125namespace Unilight
226{
327 public class Matrix4
@@ -9,220 +33,143 @@ public enum Axis { XAxis, YAxis, ZAxis };
933 public Matrix4 ( )
1034 {
1135 for ( int i = 0 ; i < 4 ; ++ i )
12- {
1336 for ( int j = 0 ; j < 4 ; ++ j )
14- {
1537 values [ i , j ] = 0 ;
16- }
17- }
1838 }
1939
20- public Matrix4 Add ( Matrix4 m )
40+ // Indexer for convenience
41+ public float this [ int i , int j ]
42+ {
43+ get => values [ i , j ] ;
44+ set => values [ i , j ] = value ;
45+ }
46+
47+ // Operator overloads
48+ public static Matrix4 operator + ( Matrix4 a , Matrix4 b )
2149 {
2250 Matrix4 result = new Matrix4 ( ) ;
2351 for ( int i = 0 ; i < 4 ; ++ i )
24- {
2552 for ( int j = 0 ; j < 4 ; ++ j )
26- {
27- result . SetAt ( i , j , values [ i , j ] + m . values [ i , j ] ) ;
28- }
29- }
53+ result [ i , j ] = a [ i , j ] + b [ i , j ] ;
3054 return result ;
3155 }
3256
33- public void IncreaseBy ( Matrix4 m )
57+ public static Matrix4 operator - ( Matrix4 a , Matrix4 b )
3458 {
59+ Matrix4 result = new Matrix4 ( ) ;
3560 for ( int i = 0 ; i < 4 ; ++ i )
36- {
3761 for ( int j = 0 ; j < 4 ; ++ j )
38- {
39- values [ i , j ] += m . values [ i , j ] ;
40- }
41- }
62+ result [ i , j ] = a [ i , j ] - b [ i , j ] ;
63+ return result ;
4264 }
4365
44- public Matrix4 Subtract ( Matrix4 m )
66+ public static Matrix4 operator * ( Matrix4 a , float scalar )
4567 {
4668 Matrix4 result = new Matrix4 ( ) ;
4769 for ( int i = 0 ; i < 4 ; ++ i )
48- {
4970 for ( int j = 0 ; j < 4 ; ++ j )
50- {
51- result . SetAt ( i , j , values [ i , j ] - m . values [ i , j ] ) ;
52- }
53- }
71+ result [ i , j ] = a [ i , j ] * scalar ;
5472 return result ;
5573 }
5674
57- public void DecreaseBy ( Matrix4 m )
75+ public static Matrix4 operator * ( Matrix4 a , Matrix4 b )
5876 {
77+ Matrix4 result = new Matrix4 ( ) ;
5978 for ( int i = 0 ; i < 4 ; ++ i )
6079 {
6180 for ( int j = 0 ; j < 4 ; ++ j )
6281 {
63- values [ i , j ] -= m . values [ i , j ] ;
82+ float sum = 0 ;
83+ for ( int k = 0 ; k < 4 ; ++ k )
84+ sum += a [ i , k ] * b [ k , j ] ;
85+ result [ i , j ] = sum ;
6486 }
6587 }
88+ return result ;
6689 }
6790
68- public void MultiplyThisBy ( float scalar )
91+ // Multiply a vector
92+ public Vector3D MultiplyBy ( Vector3D v )
6993 {
70- for ( int i = 0 ; i < 4 ; ++ i )
94+ return new Vector3D
7195 {
72- for ( int j = 0 ; j < 4 ; ++ j )
73- {
74- values [ i , j ] *= scalar ;
75- }
76- }
96+ X = values [ 0 , 0 ] * v . X + values [ 0 , 1 ] * v . Y + values [ 0 , 2 ] * v . Z + values [ 0 , 3 ] ,
97+ Y = values [ 1 , 0 ] * v . X + values [ 1 , 1 ] * v . Y + values [ 1 , 2 ] * v . Z + values [ 1 , 3 ] ,
98+ Z = values [ 2 , 0 ] * v . X + values [ 2 , 1 ] * v . Y + values [ 2 , 2 ] * v . Z + values [ 2 , 3 ]
99+ } ;
77100 }
78101
79- public Matrix4 Multiply ( Matrix4 m )
102+ // Mutable operations
103+ public void MultiplyThisBy ( Matrix4 m )
80104 {
81- Matrix4 result = new Matrix4 ( ) ;
105+ var result = this * m ;
82106 for ( int i = 0 ; i < 4 ; ++ i )
83- {
84107 for ( int j = 0 ; j < 4 ; ++ j )
85- {
86- float v = 0 ;
87- for ( int k = 0 ; k < 4 ; ++ k )
88- {
89- v += values [ i , k ] * m . values [ k , j ] ;
90- }
91- result . values [ i , j ] = v ;
92- }
93- }
94- return result ;
108+ values [ i , j ] = result [ i , j ] ;
95109 }
96110
97- public void MultiplyThisBy ( Matrix4 m )
111+ public void MultiplyThisBy ( float scalar )
98112 {
99- Matrix4 result = this . Multiply ( m ) ;
100113 for ( int i = 0 ; i < 4 ; ++ i )
101- {
102114 for ( int j = 0 ; j < 4 ; ++ j )
103- {
104- values [ i , j ] = result . values [ i , j ] ;
105- }
106- }
115+ values [ i , j ] *= scalar ;
107116 }
108117
109- public Vector3D Multiply ( Vector3D v )
118+ // ---Convenience "Load" methods (void with out parameter)
119+ public static void LoadIdentity ( out Matrix4 result )
110120 {
111- Vector3D result = new Vector3D ( ) ;
112-
113- // compute x
114- float sum = 0 ;
115- for ( int j = 0 ; j < 3 ; ++ j )
116- {
117- sum += values [ 0 , j ] * v . X ;
118- }
119- sum += values [ 0 , 3 ] ;
120- result . X = sum ;
121-
122- // compute y
123- sum = 0 ;
124- for ( int j = 0 ; j < 3 ; ++ j )
125- {
126- sum += values [ 1 , j ] * v . Y ;
127- }
128- sum += values [ 1 , 3 ] ;
129- result . Y = sum ;
130-
131- // compute z
132- sum = 0 ;
133- for ( int j = 0 ; j < 3 ; ++ j )
134- {
135- sum += values [ 2 , j ] * v . Z ;
136- }
137- sum += values [ 2 , 3 ] ;
138- result . Z = sum ;
121+ result = new Matrix4 ( ) ;
122+ result [ 0 , 0 ] = 1 ; result [ 1 , 1 ] = 1 ; result [ 2 , 2 ] = 1 ; result [ 3 , 3 ] = 1 ;
123+ }
139124
140- return result ;
125+ public static void LoadZero ( out Matrix4 result )
126+ {
127+ result = new Matrix4 ( ) ; // all elements already 0
141128 }
142129
143- public void SetAt ( int i , int j , float value )
130+ public static void LoadTranslate ( float tx , float ty , float tz , out Matrix4 result )
144131 {
145- values [ i , j ] = value ;
132+ LoadIdentity ( out result ) ;
133+ result [ 0 , 3 ] = tx ;
134+ result [ 1 , 3 ] = ty ;
135+ result [ 2 , 3 ] = tz ;
146136 }
147137
148- public float GetAt ( int i , int j )
138+ public static void LoadScale ( float sx , float sy , float sz , out Matrix4 result )
149139 {
150- return values [ i , j ] ;
140+ LoadIdentity ( out result ) ;
141+ result [ 0 , 0 ] = sx ;
142+ result [ 1 , 1 ] = sy ;
143+ result [ 2 , 2 ] = sz ;
151144 }
152145
153- // x = 0, y = 1, z = 1
154- public static Matrix4 rotate ( float angle , Matrix4 . Axis axis )
146+ public static void LoadRotate ( float angle , Axis axis , out Matrix4 result )
155147 {
156- Matrix4 result = new Matrix4 ( ) ;
157- float cosAngle = ( float ) Math . Cos ( angle ) ;
158- float sinAngle = ( float ) Math . Sin ( angle ) ; ;
148+ LoadIdentity ( out result ) ;
149+ float cos = ( float ) Math . Cos ( angle ) ;
150+ float sin = ( float ) Math . Sin ( angle ) ;
151+
159152 switch ( axis )
160153 {
161- case Matrix4 . Axis . XAxis :
162- result . SetAt ( 0 , 0 , 1 ) ;
163- result . SetAt ( 1 , 1 , cosAngle ) ;
164- result . SetAt ( 1 , 2 , sinAngle ) ;
165- result . SetAt ( 2 , 1 , - sinAngle ) ;
166- result . SetAt ( 2 , 2 , cosAngle ) ;
154+ case Axis . XAxis :
155+ result [ 1 , 1 ] = cos ; result [ 1 , 2 ] = sin ;
156+ result [ 2 , 1 ] = - sin ; result [ 2 , 2 ] = cos ;
167157 break ;
168158
169- case Matrix4 . Axis . YAxis :
170- result . SetAt ( 0 , 0 , cosAngle ) ;
171- result . SetAt ( 0 , 2 , - sinAngle ) ;
172- result . SetAt ( 1 , 1 , 1 ) ;
173- result . SetAt ( 2 , 0 , sinAngle ) ;
174- result . SetAt ( 2 , 2 , cosAngle ) ;
159+ case Axis . YAxis :
160+ result [ 0 , 0 ] = cos ; result [ 0 , 2 ] = - sin ;
161+ result [ 2 , 0 ] = sin ; result [ 2 , 2 ] = cos ;
175162 break ;
176163
177- case Matrix4 . Axis . ZAxis :
178- result . SetAt ( 0 , 0 , cosAngle ) ;
179- result . SetAt ( 0 , 1 , sinAngle ) ;
180- result . SetAt ( 1 , 0 , - sinAngle ) ;
181- result . SetAt ( 1 , 1 , cosAngle ) ;
182- result . SetAt ( 2 , 2 , 1 ) ;
164+ case Axis . ZAxis :
165+ result [ 0 , 0 ] = cos ; result [ 0 , 1 ] = sin ;
166+ result [ 1 , 0 ] = - sin ; result [ 1 , 1 ] = cos ;
183167 break ;
184168 }
185- result . SetAt ( 3 , 3 , 1 ) ;
186- return result ;
187- }
188-
189- public static Matrix4 translate ( float tx , float ty , float tz )
190- {
191- Matrix4 result = new Matrix4 ( ) ;
192- result . SetAt ( 0 , 3 , tx ) ;
193- result . SetAt ( 1 , 3 , ty ) ;
194- result . SetAt ( 2 , 3 , tz ) ;
195- result . SetAt ( 0 , 0 , 1 ) ;
196- result . SetAt ( 1 , 1 , 1 ) ;
197- result . SetAt ( 2 , 2 , 1 ) ;
198- result . SetAt ( 3 , 3 , 1 ) ;
199- return result ;
200- }
201-
202- public static Matrix4 scale ( float sx , float sy , float sz )
203- {
204- Matrix4 result = new Matrix4 ( ) ;
205- result . SetAt ( 0 , 0 , sx ) ;
206- result . SetAt ( 1 , 1 , sy ) ;
207- result . SetAt ( 2 , 2 , sz ) ;
208- result . SetAt ( 3 , 3 , 1 ) ;
209- return result ;
210- }
211-
212- public static Matrix4 zero ( )
213- {
214- return new Matrix4 ( ) ;
215169 }
216170
217- public static Matrix4 identity ( )
218- {
219- Matrix4 result = new Matrix4 ( ) ;
220- result . SetAt ( 0 , 0 , 1 ) ;
221- result . SetAt ( 1 , 1 , 1 ) ;
222- result . SetAt ( 2 , 2 , 1 ) ;
223- result . SetAt ( 3 , 3 , 1 ) ;
224- return result ;
225- }
171+ // Indexer for direct access
172+ public float GetAt ( int i , int j ) => values [ i , j ] ;
173+ public void SetAt ( int i , int j , float value ) => values [ i , j ] = value ;
226174 }
227-
228- }
175+ }
0 commit comments