Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region --- License ---
2
/*
3
Copyright (c) 2006 - 2008 The Open Toolkit library.
4
 
5
Permission is hereby granted, free of charge, to any person obtaining a copy of
6
this software and associated documentation files (the "Software"), to deal in
7
the Software without restriction, including without limitation the rights to
8
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is furnished to do
10
so, subject to the following conditions:
11
 
12
The above copyright notice and this permission notice shall be included in all
13
copies or substantial portions of the Software.
14
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
SOFTWARE.
22
 */
23
#endregion
24
 
25
using System;
26
using System.Runtime.InteropServices;
27
 
28
namespace OpenTK.Math
29
{
30
    /// <summary>
31
    /// Represents a 4x4 Matrix
32
    /// </summary>
33
    [Obsolete("OpenTK.Math functions have been moved to the root OpenTK namespace (reason: XNA compatibility")]
34
    [Serializable]
35
    [StructLayout(LayoutKind.Sequential)]
36
    public struct Matrix4 : IEquatable<Matrix4>
37
    {
38
        #region Fields
39
 
40
        /// <summary>
41
        /// Top row of the matrix
42
        /// </summary>
43
        public Vector4 Row0;
44
        /// <summary>
45
        /// 2nd row of the matrix
46
        /// </summary>
47
        public Vector4 Row1;
48
        /// <summary>
49
        /// 3rd row of the matrix
50
        /// </summary>
51
        public Vector4 Row2;
52
        /// <summary>
53
        /// Bottom row of the matrix
54
        /// </summary>
55
        public Vector4 Row3;
56
 
57
        /// <summary>
58
        /// The identity matrix
59
        /// </summary>
60
        public static Matrix4 Identity = new Matrix4(Vector4.UnitX, Vector4.UnitY, Vector4.UnitZ, Vector4.UnitW);
61
 
62
        #endregion
63
 
64
        #region Constructors
65
 
66
        /// <summary>
67
        /// Constructs a new instance.
68
        /// </summary>
69
        /// <param name="row0">Top row of the matrix</param>
70
        /// <param name="row1">Second row of the matrix</param>
71
        /// <param name="row2">Third row of the matrix</param>
72
        /// <param name="row3">Bottom row of the matrix</param>
73
        public Matrix4(Vector4 row0, Vector4 row1, Vector4 row2, Vector4 row3)
74
        {
75
            Row0 = row0;
76
            Row1 = row1;
77
            Row2 = row2;
78
            Row3 = row3;
79
        }
80
 
81
        /// <summary>
82
        /// Constructs a new instance.
83
        /// </summary>
84
        /// <param name="m00">First item of the first row of the matrix.</param>
85
        /// <param name="m01">Second item of the first row of the matrix.</param>
86
        /// <param name="m02">Third item of the first row of the matrix.</param>
87
        /// <param name="m03">Fourth item of the first row of the matrix.</param>
88
        /// <param name="m10">First item of the second row of the matrix.</param>
89
        /// <param name="m11">Second item of the second row of the matrix.</param>
90
        /// <param name="m12">Third item of the second row of the matrix.</param>
91
        /// <param name="m13">Fourth item of the second row of the matrix.</param>
92
        /// <param name="m20">First item of the third row of the matrix.</param>
93
        /// <param name="m21">Second item of the third row of the matrix.</param>
94
        /// <param name="m22">Third item of the third row of the matrix.</param>
95
        /// <param name="m23">First item of the third row of the matrix.</param>
96
        /// <param name="m30">Fourth item of the fourth row of the matrix.</param>
97
        /// <param name="m31">Second item of the fourth row of the matrix.</param>
98
        /// <param name="m32">Third item of the fourth row of the matrix.</param>
99
        /// <param name="m33">Fourth item of the fourth row of the matrix.</param>
100
        public Matrix4(
101
            float m00, float m01, float m02, float m03,
102
            float m10, float m11, float m12, float m13,
103
            float m20, float m21, float m22, float m23,
104
            float m30, float m31, float m32, float m33)
105
        {
106
            Row0 = new Vector4(m00, m01, m02, m03);
107
            Row1 = new Vector4(m10, m11, m12, m13);
108
            Row2 = new Vector4(m20, m21, m22, m23);
109
            Row3 = new Vector4(m30, m31, m32, m33);
110
        }
111
 
112
        #endregion
113
 
114
        #region Public Members
115
 
116
        #region Properties
117
 
118
        /// <summary>
119
        /// The determinant of this matrix
120
        /// </summary>
121
        public float Determinant
122
        {
123
            get
124
            {
125
                return
126
                    Row0.X * Row1.Y * Row2.Z * Row3.W - Row0.X * Row1.Y * Row2.W * Row3.Z + Row0.X * Row1.Z * Row2.W * Row3.Y - Row0.X * Row1.Z * Row2.Y * Row3.W
127
                  + Row0.X * Row1.W * Row2.Y * Row3.Z - Row0.X * Row1.W * Row2.Z * Row3.Y - Row0.Y * Row1.Z * Row2.W * Row3.X + Row0.Y * Row1.Z * Row2.X * Row3.W
128
                  - Row0.Y * Row1.W * Row2.X * Row3.Z + Row0.Y * Row1.W * Row2.Z * Row3.X - Row0.Y * Row1.X * Row2.Z * Row3.W + Row0.Y * Row1.X * Row2.W * Row3.Z
129
                  + Row0.Z * Row1.W * Row2.X * Row3.Y - Row0.Z * Row1.W * Row2.Y * Row3.X + Row0.Z * Row1.X * Row2.Y * Row3.W - Row0.Z * Row1.X * Row2.W * Row3.Y
130
                  + Row0.Z * Row1.Y * Row2.W * Row3.X - Row0.Z * Row1.Y * Row2.X * Row3.W - Row0.W * Row1.X * Row2.Y * Row3.Z + Row0.W * Row1.X * Row2.Z * Row3.Y
131
                  - Row0.W * Row1.Y * Row2.Z * Row3.X + Row0.W * Row1.Y * Row2.X * Row3.Z - Row0.W * Row1.Z * Row2.X * Row3.Y + Row0.W * Row1.Z * Row2.Y * Row3.X;
132
            }
133
        }
134
 
135
        /// <summary>
136
        /// The first column of this matrix
137
        /// </summary>
138
        public Vector4 Column0
139
        {
140
            get { return new Vector4(Row0.X, Row1.X, Row2.X, Row3.X); }
141
        }
142
 
143
        /// <summary>
144
        /// The second column of this matrix
145
        /// </summary>
146
        public Vector4 Column1
147
        {
148
            get { return new Vector4(Row0.Y, Row1.Y, Row2.Y, Row3.Y); }
149
        }
150
 
151
        /// <summary>
152
        /// The third column of this matrix
153
        /// </summary>
154
        public Vector4 Column2
155
        {
156
            get { return new Vector4(Row0.Z, Row1.Z, Row2.Z, Row3.Z); }
157
        }
158
 
159
        /// <summary>
160
        /// The fourth column of this matrix
161
        /// </summary>
162
        public Vector4 Column3
163
        {
164
            get { return new Vector4(Row0.W, Row1.W, Row2.W, Row3.W); }
165
        }
166
 
167
        /// <summary>
168
        /// Gets or sets the value at row 1, column 1 of this instance.
169
        /// </summary>
170
        public float M11 { get { return Row0.X; } set { Row0.X = value; } }
171
 
172
        /// <summary>
173
        /// Gets or sets the value at row 1, column 2 of this instance.
174
        /// </summary>
175
        public float M12 { get { return Row0.Y; } set { Row0.Y = value; } }
176
 
177
        /// <summary>
178
        /// Gets or sets the value at row 1, column 3 of this instance.
179
        /// </summary>
180
        public float M13 { get { return Row0.Z; } set { Row0.Z = value; } }
181
 
182
        /// <summary>
183
        /// Gets or sets the value at row 1, column 4 of this instance.
184
        /// </summary>
185
        public float M14 { get { return Row0.W; } set { Row0.W = value; } }
186
 
187
        /// <summary>
188
        /// Gets or sets the value at row 2, column 1 of this instance.
189
        /// </summary>
190
        public float M21 { get { return Row1.X; } set { Row1.X = value; } }
191
 
192
        /// <summary>
193
        /// Gets or sets the value at row 2, column 2 of this instance.
194
        /// </summary>
195
        public float M22 { get { return Row1.Y; } set { Row1.Y = value; } }
196
 
197
        /// <summary>
198
        /// Gets or sets the value at row 2, column 3 of this instance.
199
        /// </summary>
200
        public float M23 { get { return Row1.Z; } set { Row1.Z = value; } }
201
 
202
        /// <summary>
203
        /// Gets or sets the value at row 2, column 4 of this instance.
204
        /// </summary>
205
        public float M24 { get { return Row1.W; } set { Row1.W = value; } }
206
 
207
        /// <summary>
208
        /// Gets or sets the value at row 3, column 1 of this instance.
209
        /// </summary>
210
        public float M31 { get { return Row2.X; } set { Row2.X = value; } }
211
 
212
        /// <summary>
213
        /// Gets or sets the value at row 3, column 2 of this instance.
214
        /// </summary>
215
        public float M32 { get { return Row2.Y; } set { Row2.Y = value; } }
216
 
217
        /// <summary>
218
        /// Gets or sets the value at row 3, column 3 of this instance.
219
        /// </summary>
220
        public float M33 { get { return Row2.Z; } set { Row2.Z = value; } }
221
 
222
        /// <summary>
223
        /// Gets or sets the value at row 3, column 4 of this instance.
224
        /// </summary>
225
        public float M34 { get { return Row2.W; } set { Row2.W = value; } }
226
 
227
        /// <summary>
228
        /// Gets or sets the value at row 4, column 1 of this instance.
229
        /// </summary>
230
        public float M41 { get { return Row3.X; } set { Row3.X = value; } }
231
 
232
        /// <summary>
233
        /// Gets or sets the value at row 4, column 3 of this instance.
234
        /// </summary>
235
        public float M42 { get { return Row3.Y; } set { Row3.Y = value; } }
236
 
237
        /// <summary>
238
        /// Gets or sets the value at row 4, column 3 of this instance.
239
        /// </summary>
240
        public float M43 { get { return Row3.Z; } set { Row3.Z = value; } }
241
 
242
        /// <summary>
243
        /// Gets or sets the value at row 4, column 4 of this instance.
244
        /// </summary>
245
        public float M44 { get { return Row3.W; } set { Row3.W = value; } }
246
 
247
        #endregion
248
 
249
        #region Instance
250
 
251
        #region public void Invert()
252
 
253
        public void Invert()
254
        {
255
            this = Matrix4.Invert(this);
256
        }
257
 
258
        #endregion
259
 
260
        #region public void Transpose()
261
 
262
        /// <summary>
263
        /// Calculates the transpose of this instance.
264
        /// </summary>
265
        public void Transpose()
266
        {
267
            this = Matrix4.Transpose(this);
268
        }
269
 
270
        #endregion
271
 
272
        #endregion
273
 
274
        #region Static
275
 
276
        #region CreateFromAxisAngle
277
 
278
        /// <summary>
279
        /// Build a rotation matrix from the specified axis/angle rotation.
280
        /// </summary>
281
        /// <param name="axis">The axis to rotate about.</param>
282
        /// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
283
        /// <param name="result">A matrix instance.</param>
284
        public static void CreateFromAxisAngle(Vector3 axis, float angle, out Matrix4 result)
285
        {
286
            float cos = (float)System.Math.Cos(-angle);
287
            float sin = (float)System.Math.Sin(-angle);
288
            float t = 1.0f - cos;
289
 
290
            axis.Normalize();
291
 
292
            result = new Matrix4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f,
293
                                 t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f,
294
                                 t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f,
295
                                 0, 0, 0, 1);
296
        }
297
 
298
        /// <summary>
299
        /// Build a rotation matrix from the specified axis/angle rotation.
300
        /// </summary>
301
        /// <param name="axis">The axis to rotate about.</param>
302
        /// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
303
        /// <returns>A matrix instance.</returns>
304
        public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle)
305
        {
306
            Matrix4 result;
307
            CreateFromAxisAngle(axis, angle, out result);
308
            return result;
309
        }
310
 
311
        #endregion
312
 
313
        #region CreateTranslation
314
 
315
        /// <summary>
316
        /// Creates a translation matrix.
317
        /// </summary>
318
        /// <param name="x">X translation.</param>
319
        /// <param name="y">Y translation.</param>
320
        /// <param name="z">Z translation.</param>
321
        /// <param name="result">The resulting Matrix4 instance.</param>
322
        public static void CreateTranslation(float x, float y, float z, out Matrix4 result)
323
        {
324
            result = Identity;
325
            result.Row3 = new Vector4(x, y, z, 1);
326
        }
327
 
328
        /// <summary>
329
        /// Creates a translation matrix.
330
        /// </summary>
331
        /// <param name="vector">The translation vector.</param>
332
        /// <param name="result">The resulting Matrix4 instance.</param>
333
        public static void CreateTranslation(ref Vector3 vector, out Matrix4 result)
334
        {
335
            result = Identity;
336
            result.Row3 = new Vector4(vector.X, vector.Y, vector.Z, 1);
337
        }
338
 
339
        /// <summary>
340
        /// Creates a translation matrix.
341
        /// </summary>
342
        /// <param name="x">X translation.</param>
343
        /// <param name="y">Y translation.</param>
344
        /// <param name="z">Z translation.</param>
345
        /// <returns>The resulting Matrix4 instance.</returns>
346
        public static Matrix4 CreateTranslation(float x, float y, float z)
347
        {
348
            Matrix4 result;
349
            CreateTranslation(x, y, z, out result);
350
            return result;
351
        }
352
 
353
        /// <summary>
354
        /// Creates a translation matrix.
355
        /// </summary>
356
        /// <param name="vector">The translation vector.</param>
357
        /// <returns>The resulting Matrix4 instance.</returns>
358
        public static Matrix4 CreateTranslation(Vector3 vector)
359
        {
360
            Matrix4 result;
361
            CreateTranslation(vector.X, vector.Y, vector.Z, out result);
362
            return result;
363
        }
364
 
365
        #endregion
366
 
367
        #region CreateOrthographic
368
 
369
        /// <summary>
370
        /// Creates an orthographic projection matrix.
371
        /// </summary>
372
        /// <param name="width">The width of the projection volume.</param>
373
        /// <param name="height">The height of the projection volume.</param>
374
        /// <param name="zNear">The near edge of the projection volume.</param>
375
        /// <param name="zFar">The far edge of the projection volume.</param>
376
        /// <param name="result">The resulting Matrix4 instance.</param>
377
        public static void CreateOrthographic(float width, float height, float zNear, float zFar, out Matrix4 result)
378
        {
379
            CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
380
        }
381
 
382
        /// <summary>
383
        /// Creates an orthographic projection matrix.
384
        /// </summary>
385
        /// <param name="width">The width of the projection volume.</param>
386
        /// <param name="height">The height of the projection volume.</param>
387
        /// <param name="zNear">The near edge of the projection volume.</param>
388
        /// <param name="zFar">The far edge of the projection volume.</param>
389
        /// <rereturns>The resulting Matrix4 instance.</rereturns>
390
        public static Matrix4 CreateOrthographic(float width, float height, float zNear, float zFar)
391
        {
392
            Matrix4 result;
393
            CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
394
            return result;
395
        }
396
 
397
        #endregion
398
 
399
        #region CreateOrthographicOffCenter
400
 
401
        /// <summary>
402
        /// Creates an orthographic projection matrix.
403
        /// </summary>
404
        /// <param name="left">The left edge of the projection volume.</param>
405
        /// <param name="right">The right edge of the projection volume.</param>
406
        /// <param name="bottom">The bottom edge of the projection volume.</param>
407
        /// <param name="top">The top edge of the projection volume.</param>
408
        /// <param name="zNear">The near edge of the projection volume.</param>
409
        /// <param name="zFar">The far edge of the projection volume.</param>
410
        /// <param name="result">The resulting Matrix4 instance.</param>
411
        public static void CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result)
412
        {
413
            result = new Matrix4();
414
 
415
            float invRL = 1 / (right - left);
416
            float invTB = 1 / (top - bottom);
417
            float invFN = 1 / (zFar - zNear);
418
 
419
            result.M11 = 2 * invRL;
420
            result.M22 = 2 * invTB;
421
            result.M33 = -2 * invFN;
422
 
423
            result.M41 = -(right + left) * invRL;
424
            result.M42 = -(top + bottom) * invTB;
425
            result.M43 = -(zFar + zNear) * invFN;
426
            result.M44 = 1;
427
        }
428
 
429
        /// <summary>
430
        /// Creates an orthographic projection matrix.
431
        /// </summary>
432
        /// <param name="left">The left edge of the projection volume.</param>
433
        /// <param name="right">The right edge of the projection volume.</param>
434
        /// <param name="bottom">The bottom edge of the projection volume.</param>
435
        /// <param name="top">The top edge of the projection volume.</param>
436
        /// <param name="zNear">The near edge of the projection volume.</param>
437
        /// <param name="zFar">The far edge of the projection volume.</param>
438
        /// <returns>The resulting Matrix4 instance.</returns>
439
        public static Matrix4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar)
440
        {
441
            Matrix4 result;
442
            CreateOrthographicOffCenter(left, right, bottom, top, zNear, zFar, out result);
443
            return result;
444
        }
445
 
446
        #endregion
447
 
448
        #region CreatePerspectiveFieldOfView
449
 
450
        /// <summary>
451
        /// Creates a perspective projection matrix.
452
        /// </summary>
453
        /// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
454
        /// <param name="aspect">Aspect ratio of the view (width / height)</param>
455
        /// <param name="zNear">Distance to the near clip plane</param>
456
        /// <param name="zFar">Distance to the far clip plane</param>
457
        /// <param name="result">A projection matrix that transforms camera space to raster space</param>
458
        /// <exception cref="System.ArgumentOutOfRangeException">
459
        /// Thrown under the following conditions:
460
        /// <list type="bullet">
461
        /// <item>fovy is zero, less than zero or larger than Math.PI</item>
462
        /// <item>aspect is negative or zero</item>
463
        /// <item>zNear is negative or zero</item>
464
        /// <item>zFar is negative or zero</item>
465
        /// <item>zNear is larger than zFar</item>
466
        /// </list>
467
        /// </exception>
468
        public static void CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar, out Matrix4 result)
469
        {
470
            if (fovy <= 0 || fovy > System.Math.PI)
471
                throw new ArgumentOutOfRangeException("fovy");
472
            if (aspect <= 0)
473
                throw new ArgumentOutOfRangeException("aspect");
474
            if (zNear <= 0)
475
                throw new ArgumentOutOfRangeException("zNear");
476
            if (zFar <= 0)
477
                throw new ArgumentOutOfRangeException("zFar");
478
            if (zNear >= zFar)
479
                throw new ArgumentOutOfRangeException("zNear");
480
 
481
            float yMax = zNear * (float)System.Math.Tan(0.5f * fovy);
482
            float yMin = -yMax;
483
            float xMin = yMin * aspect;
484
            float xMax = yMax * aspect;
485
 
486
            CreatePerspectiveOffCenter(xMin, xMax, yMin, yMax, zNear, zFar, out result);
487
        }
488
 
489
        /// <summary>
490
        /// Creates a perspective projection matrix.
491
        /// </summary>
492
        /// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
493
        /// <param name="aspect">Aspect ratio of the view (width / height)</param>
494
        /// <param name="zNear">Distance to the near clip plane</param>
495
        /// <param name="zFar">Distance to the far clip plane</param>
496
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
497
        /// <exception cref="System.ArgumentOutOfRangeException">
498
        /// Thrown under the following conditions:
499
        /// <list type="bullet">
500
        /// <item>fovy is zero, less than zero or larger than Math.PI</item>
501
        /// <item>aspect is negative or zero</item>
502
        /// <item>zNear is negative or zero</item>
503
        /// <item>zFar is negative or zero</item>
504
        /// <item>zNear is larger than zFar</item>
505
        /// </list>
506
        /// </exception>
507
        public static Matrix4 CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar)
508
        {
509
            Matrix4 result;
510
            CreatePerspectiveFieldOfView(fovy, aspect, zNear, zFar, out result);
511
            return result;
512
        }
513
 
514
        #endregion
515
 
516
        #region CreatePerspectiveOffCenter
517
 
518
        /// <summary>
519
        /// Creates an perspective projection matrix.
520
        /// </summary>
521
        /// <param name="left">Left edge of the view frustum</param>
522
        /// <param name="right">Right edge of the view frustum</param>
523
        /// <param name="bottom">Bottom edge of the view frustum</param>
524
        /// <param name="top">Top edge of the view frustum</param>
525
        /// <param name="zNear">Distance to the near clip plane</param>
526
        /// <param name="zFar">Distance to the far clip plane</param>
527
        /// <param name="result">A projection matrix that transforms camera space to raster space</param>
528
        /// <exception cref="System.ArgumentOutOfRangeException">
529
        /// Thrown under the following conditions:
530
        /// <list type="bullet">
531
        /// <item>zNear is negative or zero</item>
532
        /// <item>zFar is negative or zero</item>
533
        /// <item>zNear is larger than zFar</item>
534
        /// </list>
535
        /// </exception>
536
        public static void CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result)
537
        {
538
            if (zNear <= 0)
539
                throw new ArgumentOutOfRangeException("zNear");
540
            if (zFar <= 0)
541
                throw new ArgumentOutOfRangeException("zFar");
542
            if (zNear >= zFar)
543
                throw new ArgumentOutOfRangeException("zNear");
544
 
545
            float x = (2.0f * zNear) / (right - left);
546
            float y = (2.0f * zNear) / (top - bottom);
547
            float a = (right + left) / (right - left);
548
            float b = (top + bottom) / (top - bottom);
549
            float c = -(zFar + zNear) / (zFar - zNear);
550
            float d = -(2.0f * zFar * zNear) / (zFar - zNear);
551
 
552
            result = new Matrix4(x, 0, 0,  0,
553
                                 0, y, 0,  0,
554
                                 a, b, c, -1,
555
                                 0, 0, d,  0);
556
        }
557
 
558
        /// <summary>
559
        /// Creates an perspective projection matrix.
560
        /// </summary>
561
        /// <param name="left">Left edge of the view frustum</param>
562
        /// <param name="right">Right edge of the view frustum</param>
563
        /// <param name="bottom">Bottom edge of the view frustum</param>
564
        /// <param name="top">Top edge of the view frustum</param>
565
        /// <param name="zNear">Distance to the near clip plane</param>
566
        /// <param name="zFar">Distance to the far clip plane</param>
567
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
568
        /// <exception cref="System.ArgumentOutOfRangeException">
569
        /// Thrown under the following conditions:
570
        /// <list type="bullet">
571
        /// <item>zNear is negative or zero</item>
572
        /// <item>zFar is negative or zero</item>
573
        /// <item>zNear is larger than zFar</item>
574
        /// </list>
575
        /// </exception>
576
        public static Matrix4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar)
577
        {
578
            Matrix4 result;
579
            CreatePerspectiveOffCenter(left, right, bottom, top, zNear, zFar, out result);
580
            return result;
581
        }
582
 
583
        #endregion
584
 
585
        #region Obsolete Functions
586
 
587
        #region Translation Functions
588
 
589
        /// <summary>
590
        /// Builds a translation matrix.
591
        /// </summary>
592
        /// <param name="trans">The translation vector.</param>
593
        /// <returns>A new Matrix4 instance.</returns>
594
        [Obsolete("Use CreateTranslation instead.")]
595
        public static Matrix4 Translation(Vector3 trans)
596
        {
597
            return Translation(trans.X, trans.Y, trans.Z);
598
        }
599
 
600
        /// <summary>
601
        /// Build a translation matrix with the given translation
602
        /// </summary>
603
        /// <param name="x">X translation</param>
604
        /// <param name="y">Y translation</param>
605
        /// <param name="z">Z translation</param>
606
        /// <returns>A Translation matrix</returns>
607
        [Obsolete("Use CreateTranslation instead.")]
608
        public static Matrix4 Translation(float x, float y, float z)
609
        {
610
            Matrix4 result = Identity;
611
            result.Row3 = new Vector4(x, y, z, 1.0f);
612
            return result;
613
        }
614
 
615
        #endregion
616
 
617
        #endregion
618
 
619
        #region Scale Functions
620
 
621
        /// <summary>
622
        /// Build a scaling matrix
623
        /// </summary>
624
        /// <param name="scale">Single scale factor for x,y and z axes</param>
625
        /// <returns>A scaling matrix</returns>
626
        public static Matrix4 Scale(float scale)
627
        {
628
            return Scale(scale, scale, scale);
629
        }
630
 
631
        /// <summary>
632
        /// Build a scaling matrix
633
        /// </summary>
634
        /// <param name="scale">Scale factors for x,y and z axes</param>
635
        /// <returns>A scaling matrix</returns>
636
        public static Matrix4 Scale(Vector3 scale)
637
        {
638
            return Scale(scale.X, scale.Y, scale.Z);
639
        }
640
 
641
        /// <summary>
642
        /// Build a scaling matrix
643
        /// </summary>
644
        /// <param name="x">Scale factor for x-axis</param>
645
        /// <param name="y">Scale factor for y-axis</param>
646
        /// <param name="z">Scale factor for z-axis</param>
647
        /// <returns>A scaling matrix</returns>
648
        public static Matrix4 Scale(float x, float y, float z)
649
        {
650
            Matrix4 result;
651
            result.Row0 = Vector4.UnitX * x;
652
            result.Row1 = Vector4.UnitY * y;
653
            result.Row2 = Vector4.UnitZ * z;
654
            result.Row3 = Vector4.UnitW;
655
            return result;
656
        }
657
 
658
        #endregion
659
 
660
        #region Rotation Functions
661
 
662
        /// <summary>
663
        /// Build a rotation matrix that rotates about the x-axis
664
        /// </summary>
665
        /// <param name="angle">angle in radians to rotate counter-clockwise around the x-axis</param>
666
        /// <returns>A rotation matrix</returns>
667
        [Obsolete("Use CreateRotationX instead.")]
668
        public static Matrix4 RotateX(float angle)
669
        {
670
            float cos = (float)System.Math.Cos(angle);
671
            float sin = (float)System.Math.Sin(angle);
672
 
673
            Matrix4 result;
674
            result.Row0 = Vector4.UnitX;
675
            result.Row1 = new Vector4(0.0f, cos, sin, 0.0f);
676
            result.Row2 = new Vector4(0.0f, -sin, cos, 0.0f);
677
            result.Row3 = Vector4.UnitW;
678
            return result;
679
        }
680
 
681
        /// <summary>
682
        /// Build a rotation matrix that rotates about the y-axis
683
        /// </summary>
684
        /// <param name="angle">angle in radians to rotate counter-clockwise around the y-axis</param>
685
        /// <returns>A rotation matrix</returns>
686
        [Obsolete("Use CreateRotationY instead.")]
687
        public static Matrix4 RotateY(float angle)
688
        {
689
            float cos = (float)System.Math.Cos(angle);
690
            float sin = (float)System.Math.Sin(angle);
691
 
692
            Matrix4 result;
693
            result.Row0 = new Vector4(cos, 0.0f, -sin, 0.0f);
694
            result.Row1 = Vector4.UnitY;
695
            result.Row2 = new Vector4(sin, 0.0f, cos, 0.0f);
696
            result.Row3 = Vector4.UnitW;
697
            return result;
698
        }
699
 
700
        /// <summary>
701
        /// Build a rotation matrix that rotates about the z-axis
702
        /// </summary>
703
        /// <param name="angle">angle in radians to rotate counter-clockwise around the z-axis</param>
704
        /// <returns>A rotation matrix</returns>
705
        [Obsolete("Use CreateRotationZ instead.")]
706
        public static Matrix4 RotateZ(float angle)
707
        {
708
            float cos = (float)System.Math.Cos(angle);
709
            float sin = (float)System.Math.Sin(angle);
710
 
711
            Matrix4 result;
712
            result.Row0 = new Vector4(cos, sin, 0.0f, 0.0f);
713
            result.Row1 = new Vector4(-sin, cos, 0.0f, 0.0f);
714
            result.Row2 = Vector4.UnitZ;
715
            result.Row3 = Vector4.UnitW;
716
            return result;
717
        }
718
 
719
        /// <summary>
720
        /// Build a rotation matrix to rotate about the given axis
721
        /// </summary>
722
        /// <param name="axis">the axis to rotate about</param>
723
        /// <param name="angle">angle in radians to rotate counter-clockwise (looking in the direction of the given axis)</param>
724
        /// <returns>A rotation matrix</returns>
725
        [Obsolete("Use CreateFromAxisAngle instead.")]
726
        public static Matrix4 Rotate(Vector3 axis, float angle)
727
        {
728
            float cos = (float)System.Math.Cos(-angle);
729
            float sin = (float)System.Math.Sin(-angle);
730
            float t = 1.0f - cos;
731
 
732
            axis.Normalize();
733
 
734
            Matrix4 result;
735
            result.Row0 = new Vector4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f);
736
            result.Row1 = new Vector4(t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f);
737
            result.Row2 = new Vector4(t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f);
738
            result.Row3 = Vector4.UnitW;
739
            return result;
740
        }
741
 
742
        /// <summary>
743
        /// Build a rotation matrix from a quaternion
744
        /// </summary>
745
        /// <param name="q">the quaternion</param>
746
        /// <returns>A rotation matrix</returns>
747
        public static Matrix4 Rotate(Quaternion q)
748
        {
749
            Vector3 axis;
750
            float angle;
751
            q.ToAxisAngle(out axis, out angle);
752
            return Rotate(axis, angle);
753
        }
754
 
755
        #endregion
756
 
757
        #region Camera Helper Functions
758
 
759
        /// <summary>
760
        /// Build a world space to camera space matrix
761
        /// </summary>
762
        /// <param name="eye">Eye (camera) position in world space</param>
763
        /// <param name="target">Target position in world space</param>
764
        /// <param name="up">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
765
        /// <returns>A Matrix4 that transforms world space to camera space</returns>
766
        public static Matrix4 LookAt(Vector3 eye, Vector3 target, Vector3 up)
767
        {
768
            Vector3 z = Vector3.Normalize(eye - target);
769
            Vector3 x = Vector3.Normalize(Vector3.Cross(up, z));
770
            Vector3 y = Vector3.Normalize(Vector3.Cross(z, x));
771
 
772
            Matrix4 rot = new Matrix4(new Vector4(x.X, y.X, z.X, 0.0f),
773
                                        new Vector4(x.Y, y.Y, z.Y, 0.0f),
774
                                        new Vector4(x.Z, y.Z, z.Z, 0.0f),
775
                                        Vector4.UnitW);
776
 
777
            Matrix4 trans = Matrix4.CreateTranslation(-eye);
778
 
779
            return trans * rot;
780
        }
781
 
782
        /// <summary>
783
        /// Build a world space to camera space matrix
784
        /// </summary>
785
        /// <param name="eyeX">Eye (camera) position in world space</param>
786
        /// <param name="eyeY">Eye (camera) position in world space</param>
787
        /// <param name="eyeZ">Eye (camera) position in world space</param>
788
        /// <param name="targetX">Target position in world space</param>
789
        /// <param name="targetY">Target position in world space</param>
790
        /// <param name="targetZ">Target position in world space</param>
791
        /// <param name="upX">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
792
        /// <param name="upY">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
793
        /// <param name="upZ">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
794
        /// <returns>A Matrix4 that transforms world space to camera space</returns>
795
        public static Matrix4 LookAt(float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ, float upX, float upY, float upZ)
796
        {
797
            return LookAt(new Vector3(eyeX, eyeY, eyeZ), new Vector3(targetX, targetY, targetZ), new Vector3(upX, upY, upZ));
798
        }
799
 
800
        /// <summary>
801
        /// Build a projection matrix
802
        /// </summary>
803
        /// <param name="left">Left edge of the view frustum</param>
804
        /// <param name="right">Right edge of the view frustum</param>
805
        /// <param name="bottom">Bottom edge of the view frustum</param>
806
        /// <param name="top">Top edge of the view frustum</param>
807
        /// <param name="near">Distance to the near clip plane</param>
808
        /// <param name="far">Distance to the far clip plane</param>
809
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
810
        [Obsolete("Use CreatePerspectiveOffCenter instead.")]
811
        public static Matrix4 Frustum(float left, float right, float bottom, float top, float near, float far)
812
        {
813
            float invRL = 1.0f / (right - left);
814
            float invTB = 1.0f / (top - bottom);
815
            float invFN = 1.0f / (far - near);
816
            return new Matrix4(new Vector4(2.0f * near * invRL, 0.0f, 0.0f, 0.0f),
817
                               new Vector4(0.0f, 2.0f * near * invTB, 0.0f, 0.0f),
818
                               new Vector4((right + left) * invRL, (top + bottom) * invTB, -(far + near) * invFN, -1.0f),
819
                               new Vector4(0.0f, 0.0f, -2.0f * far * near * invFN, 0.0f));
820
        }
821
 
822
        /// <summary>
823
        /// Build a projection matrix
824
        /// </summary>
825
        /// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
826
        /// <param name="aspect">Aspect ratio of the view (width / height)</param>
827
        /// <param name="near">Distance to the near clip plane</param>
828
        /// <param name="far">Distance to the far clip plane</param>
829
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
830
        [Obsolete("Use CreatePerspectiveFieldOfView instead.")]
831
        public static Matrix4 Perspective(float fovy, float aspect, float near, float far)
832
        {
833
            float yMax = near * (float)System.Math.Tan(0.5f * fovy);
834
            float yMin = -yMax;
835
            float xMin = yMin * aspect;
836
            float xMax = yMax * aspect;
837
 
838
            return Frustum(xMin, xMax, yMin, yMax, near, far);
839
        }
840
 
841
        #endregion
842
 
843
        #region Multiply Functions
844
 
845
        /// <summary>
846
        /// Multiplies two instances.
847
        /// </summary>
848
        /// <param name="left">The left operand of the multiplication.</param>
849
        /// <param name="right">The right operand of the multiplication.</param>
850
        /// <returns>A new instance that is the result of the multiplication</returns>
851
        public static Matrix4 Mult(Matrix4 left, Matrix4 right)
852
        {
853
            Matrix4 result;
854
            Mult(ref left, ref right, out result);
855
            return result;
856
        }
857
 
858
        /// <summary>
859
        /// Multiplies two instances.
860
        /// </summary>
861
        /// <param name="left">The left operand of the multiplication.</param>
862
        /// <param name="right">The right operand of the multiplication.</param>
863
        /// <param name="result">A new instance that is the result of the multiplication</param>
864
        public static void Mult(ref Matrix4 left, ref Matrix4 right, out Matrix4 result)
865
        {
866
            result = new Matrix4(
867
                left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41,
868
                left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42,
869
                left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43,
870
                left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44,
871
                left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41,
872
                left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42,
873
                left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43,
874
                left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44,
875
                left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41,
876
                left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42,
877
                left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43,
878
                left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44,
879
                left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41,
880
                left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42,
881
                left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43,
882
                left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44);
883
        }
884
 
885
        #endregion
886
 
887
        #region Invert Functions
888
 
889
        /// <summary>
890
        /// Calculate the inverse of the given matrix
891
        /// </summary>
892
        /// <param name="mat">The matrix to invert</param>
893
        /// <returns>The inverse of the given matrix if it has one, or the input if it is singular</returns>
894
        /// <exception cref="InvalidOperationException">Thrown if the Matrix4 is singular.</exception>
895
        public static Matrix4 Invert(Matrix4 mat)
896
        {
897
            int[] colIdx = { 0, 0, 0, 0 };
898
            int[] rowIdx = { 0, 0, 0, 0 };
899
            int[] pivotIdx = { -1, -1, -1, -1 };
900
 
901
            // convert the matrix to an array for easy looping
902
            float[,] inverse = {{mat.Row0.X, mat.Row0.Y, mat.Row0.Z, mat.Row0.W},
903
                                {mat.Row1.X, mat.Row1.Y, mat.Row1.Z, mat.Row1.W},
904
                                {mat.Row2.X, mat.Row2.Y, mat.Row2.Z, mat.Row2.W},
905
                                {mat.Row3.X, mat.Row3.Y, mat.Row3.Z, mat.Row3.W} };
906
            int icol = 0;
907
            int irow = 0;
908
            for (int i = 0; i < 4; i++)
909
            {
910
                // Find the largest pivot value
911
                float maxPivot = 0.0f;
912
                for (int j = 0; j < 4; j++)
913
                {
914
                    if (pivotIdx[j] != 0)
915
                    {
916
                        for (int k = 0; k < 4; ++k)
917
                        {
918
                            if (pivotIdx[k] == -1)
919
                            {
920
                                float absVal = System.Math.Abs(inverse[j, k]);
921
                                if (absVal > maxPivot)
922
                                {
923
                                    maxPivot = absVal;
924
                                    irow = j;
925
                                    icol = k;
926
                                }
927
                            }
928
                            else if (pivotIdx[k] > 0)
929
                            {
930
                                return mat;
931
                            }
932
                        }
933
                    }
934
                }
935
 
936
                ++(pivotIdx[icol]);
937
 
938
                // Swap rows over so pivot is on diagonal
939
                if (irow != icol)
940
                {
941
                    for (int k = 0; k < 4; ++k)
942
                    {
943
                        float f = inverse[irow, k];
944
                        inverse[irow, k] = inverse[icol, k];
945
                        inverse[icol, k] = f;
946
                    }
947
                }
948
 
949
                rowIdx[i] = irow;
950
                colIdx[i] = icol;
951
 
952
                float pivot = inverse[icol, icol];
953
                // check for singular matrix
954
                if (pivot == 0.0f)
955
                {
956
                    throw new InvalidOperationException("Matrix is singular and cannot be inverted.");
957
                    //return mat;
958
                }
959
 
960
                // Scale row so it has a unit diagonal
961
                float oneOverPivot = 1.0f / pivot;
962
                inverse[icol, icol] = 1.0f;
963
                for (int k = 0; k < 4; ++k)
964
                    inverse[icol, k] *= oneOverPivot;
965
 
966
                // Do elimination of non-diagonal elements
967
                for (int j = 0; j < 4; ++j)
968
                {
969
                    // check this isn't on the diagonal
970
                    if (icol != j)
971
                    {
972
                        float f = inverse[j, icol];
973
                        inverse[j, icol] = 0.0f;
974
                        for (int k = 0; k < 4; ++k)
975
                            inverse[j, k] -= inverse[icol, k] * f;
976
                    }
977
                }
978
            }
979
 
980
            for (int j = 3; j >= 0; --j)
981
            {
982
                int ir = rowIdx[j];
983
                int ic = colIdx[j];
984
                for (int k = 0; k < 4; ++k)
985
                {
986
                    float f = inverse[k, ir];
987
                    inverse[k, ir] = inverse[k, ic];
988
                    inverse[k, ic] = f;
989
                }
990
            }
991
 
992
            mat.Row0 = new Vector4(inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3]);
993
            mat.Row1 = new Vector4(inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3]);
994
            mat.Row2 = new Vector4(inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3]);
995
            mat.Row3 = new Vector4(inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]);
996
            return mat;
997
        }
998
 
999
        #endregion
1000
 
1001
        #region Transpose
1002
 
1003
        /// <summary>
1004
        /// Calculate the transpose of the given matrix
1005
        /// </summary>
1006
        /// <param name="mat">The matrix to transpose</param>
1007
        /// <returns>The transpose of the given matrix</returns>
1008
        public static Matrix4 Transpose(Matrix4 mat)
1009
        {
1010
            return new Matrix4(mat.Column0, mat.Column1, mat.Column2, mat.Column3);
1011
        }
1012
 
1013
 
1014
        /// <summary>
1015
        /// Calculate the transpose of the given matrix
1016
        /// </summary>
1017
        /// <param name="mat">The matrix to transpose</param>
1018
        /// <param name="result">The result of the calculation</param>
1019
        public static void Transpose(ref Matrix4 mat, out Matrix4 result)
1020
        {
1021
            result.Row0 = mat.Column0;
1022
            result.Row1 = mat.Column1;
1023
            result.Row2 = mat.Column2;
1024
            result.Row3 = mat.Column3;
1025
        }
1026
 
1027
        #endregion
1028
 
1029
        #endregion
1030
 
1031
        #region Operators
1032
 
1033
        /// <summary>
1034
        /// Matrix multiplication
1035
        /// </summary>
1036
        /// <param name="left">left-hand operand</param>
1037
        /// <param name="right">right-hand operand</param>
1038
        /// <returns>A new Matrix44 which holds the result of the multiplication</returns>
1039
        public static Matrix4 operator *(Matrix4 left, Matrix4 right)
1040
        {
1041
            return Matrix4.Mult(left, right);
1042
        }
1043
 
1044
        public static bool operator ==(Matrix4 left, Matrix4 right)
1045
        {
1046
            return left.Equals(right);
1047
        }
1048
 
1049
        public static bool operator !=(Matrix4 left, Matrix4 right)
1050
        {
1051
            return !left.Equals(right);
1052
        }
1053
 
1054
        #endregion
1055
 
1056
        #region Overrides
1057
 
1058
        #region public override string ToString()
1059
 
1060
        /// <summary>
1061
        /// Returns a System.String that represents the current Matrix44.
1062
        /// </summary>
1063
        /// <returns></returns>
1064
        public override string ToString()
1065
        {
1066
            return String.Format("{0}\n{1}\n{2}\n{3}", Row0, Row1, Row2, Row3);
1067
        }
1068
 
1069
        #endregion
1070
 
1071
        #region public override int GetHashCode()
1072
 
1073
        /// <summary>
1074
        /// Returns the hashcode for this instance.
1075
        /// </summary>
1076
        /// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
1077
        public override int GetHashCode()
1078
        {
1079
            return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode() ^ Row3.GetHashCode();
1080
        }
1081
 
1082
        #endregion
1083
 
1084
        #region public override bool Equals(object obj)
1085
 
1086
        /// <summary>
1087
        /// Indicates whether this instance and a specified object are equal.
1088
        /// </summary>
1089
        /// <param name="obj">The object to compare tresult.</param>
1090
        /// <returns>True if the instances are equal; false otherwise.</returns>
1091
        public override bool Equals(object obj)
1092
        {
1093
            if (!(obj is Matrix4))
1094
                return false;
1095
 
1096
            return this.Equals((Matrix4)obj);
1097
        }
1098
 
1099
        #endregion
1100
 
1101
        #endregion
1102
 
1103
        #endregion
1104
 
1105
        #region IEquatable<Matrix4> Members
1106
 
1107
        /// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
1108
        /// <param name="other">An matrix to compare with this matrix.</param>
1109
        /// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
1110
        public bool Equals(Matrix4 other)
1111
        {
1112
            return
1113
                Row0 == other.Row0 &&
1114
                Row1 == other.Row1 &&
1115
                Row2 == other.Row2 &&
1116
                Row3 == other.Row3;
1117
        }
1118
 
1119
        #endregion
1120
    }
1121
}