MathgeomGLS

Форк
0
/
Neslib.FastMath.pas 
4846 строк · 178.6 Кб
1
unit Neslib.FastMath;
2
{< Fast Math Library for Delphi.
3

4
  You can set these conditional defines to modify the behavior of this library:
5
  * FM_COLUMN_MAJOR: Store matrices in column-major order. Be default, matrices
6
    are store in row-major order for compatibility with the Delphi RTL. However,
7
    for OpenGL applications, it makes more sense to store matrices in column-
8
    major order. Another side effect of this define is that the depth of camera
9
    matrices are clipped to -1..1 (common with OpenGL) instead of 0..1 (uses
10
    by the Delphi RTL).
11
  * FM_NOSIMD: Disable SIMD (SSE2, NEON, ARM64) optimizations and run all
12
    calculations using Pascal code only. You will generally only enable this
13
    define for (performance) testing, or when running on an old PC that does
14
    not have support for SSE2. }
15

16
{ Copyright (c) 2016 by Erik van Bilsen
17
  All rights reserved.
18

19
Redistribution and use in source and binary forms, with or without
20
modification, are permitted provided that the following conditions are met:
21

22
1. Redistributions of source code must retain the above copyright notice, this
23
   list of conditions and the following disclaimer.
24
2. Redistributions in binary form must reproduce the above copyright notice,
25
   this list of conditions and the following disclaimer in the documentation
26
   and/or other materials provided with the distribution.
27

28
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
32
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. }
38

39
{$INCLUDE 'Neslib.FastMath.inc'}
40

41
interface
42

43
uses
44
  System.Math,
45
  System.Math.Vectors,
46
  System.Types;
47

48
const
49
  { Default tolerance for comparing small floating-point values. }
50
  SINGLE_TOLERANCE = 0.000001;
51

52
type
53
  { A 2-dimensional vector. Can be used to represent points or vectors in
54
    2D space, using the X and Y fields. You can also use it to represent
55
    texture coordinates, by using S and T (these are just aliases for X and Y).
56
    It can also be used to group 2 arbitrary values together in an array (using
57
    C[0] and C[1], which are also just aliases for X and Y).
58

59
    TVector2 is compatible with TPointF in the Delphi RTL. You can typecast
60
    between these two types or implicitly convert from one to the other through
61
    assignment (eg. MyVector2 := MyPointF). }
62
  TVector2 = record
63
  {$REGION 'Internal Declarations'}
64
  private
65
    function GetComponent(const AIndex: Integer): Single; inline;
66
    procedure SetComponent(const AIndex: Integer; const Value: Single); inline;
67
    function GetLength: Single; inline;
68
    procedure SetLength(const AValue: Single); inline;
69
    function GetLengthSquared: Single; inline;
70
    procedure SetLengthSquared(const AValue: Single); inline;
71
    function GetAngle: Single; inline;
72
    procedure SetAngle(const AValue: Single); inline;
73
  {$ENDREGION 'Internal Declarations'}
74
  public
75
    { Sets the two elements (X and Y) to 0. }
76
    procedure Init; overload; inline;
77

78
    { Sets the two elements (X and Y) to A.
79

80
      Parameters:
81
        A: the value to set the two elements to. }
82
    procedure Init(const A: Single); overload; inline;
83

84
    { Sets the two elements (X and Y) to A1 and A2 respectively.
85

86
      Parameters:
87
        A1: the value to set the first element to.
88
        A2: the value to set the second element to. }
89
    procedure Init(const A1, A2: Single); overload; inline;
90

91
    { Converts a TPoint to a TVector2.
92

93
      Parameters:
94
        APoint: the TPoint to convert. }
95
    procedure Init(const APoint: TPoint); overload; inline;
96

97
    { Implicitly converts a TPointF to a TVector2. }
98
    class operator Implicit(const A: TPointF): TVector2; inline;
99

100
    { Implicitly converts a TVector2 to a TPointF. }
101
    class operator Implicit(const A: TVector2): TPointF; inline;
102

103
    { Checks two vectors for equality.
104

105
      Returns:
106
        True if the two vectors match each other exactly. }
107
    class operator Equal(const A, B: TVector2): Boolean; inline;
108

109
    { Checks two vectors for inequality.
110

111
      Returns:
112
        True if the two vectors are not equal. }
113
    class operator NotEqual(const A, B: TVector2): Boolean; inline;
114

115
    { Negates a vector.
116

117
      Returns:
118
        The negative value of a vector (eg. (-A.X, -A.Y)) }
119
    class operator Negative(const A: TVector2): TVector2; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
120

121
    { Adds a scalar value to a vector.
122

123
      Returns:
124
        (A.X + B, A.Y + B) }
125
    class operator Add(const A: TVector2; const B: Single): TVector2; inline;
126

127
    { Adds a vector to a scalar value.
128

129
      Returns:
130
        (A + B.X, A + B.Y) }
131
    class operator Add(const A: Single; const B: TVector2): TVector2; inline;
132

133
    { Adds two vectors.
134

135
      Returns:
136
        (A.X + B.X, A.Y + B.Y) }
137
    class operator Add(const A, B: TVector2): TVector2; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
138

139
    { Subtracts a scalar value from a vector.
140

141
      Returns:
142
        (A.X - B, A.Y - B) }
143
    class operator Subtract(const A: TVector2; const B: Single): TVector2; inline;
144

145
    { Subtracts a vector from a scalar value.
146

147
      Returns:
148
        (A - B.X, A - B.Y) }
149
    class operator Subtract(const A: Single; const B: TVector2): TVector2; inline;
150

151
    { Subtracts two vectors.
152

153
      Returns:
154
        (A.X - B.X, A.Y - B.Y) }
155
    class operator Subtract(const A, B: TVector2): TVector2; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
156

157
    { Multiplies a vector with a scalar value.
158

159
      Returns:
160
        (A.X * B, A.Y * B) }
161
    class operator Multiply(const A: TVector2; const B: Single): TVector2; inline;
162

163
    { Multiplies a scalar value with a vector.
164

165
      Returns:
166
        (A * B.X, A * B.Y) }
167
    class operator Multiply(const A: Single; const B: TVector2): TVector2; inline;
168

169
    { Multiplies two vectors component-wise.
170
      To calculate a dot or cross product instead, use the Dot or Cross function.
171

172
      Returns:
173
        (A.X * B.X, A.Y * B.Y) }
174
    class operator Multiply(const A, B: TVector2): TVector2; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
175

176
    { Divides a vector by a scalar value.
177

178
      Returns:
179
        (A.X / B, A.Y / B) }
180
    class operator Divide(const A: TVector2; const B: Single): TVector2; {$IF Defined(FM_INLINE) or Defined(CPUX86)}inline;{$ENDIF}
181

182
    { Divides a scalar value by a vector.
183

184
      Returns:
185
        (A / B.X, A / B.Y) }
186
    class operator Divide(const A: Single; const B: TVector2): TVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
187

188
    { Divides two vectors component-wise.
189

190
      Returns:
191
        (A.X / B.X, A.Y / B.Y) }
192
    class operator Divide(const A, B: TVector2): TVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
193

194
    { Whether this vector equals another vector, within a certain tolerance.
195

196
      Parameters:
197
        AOther: the other vector.
198
        ATolerance: (optional) tolerance. If not specified, a small tolerance
199
          is used.
200

201
      Returns:
202
        True if both vectors are equal (within the given tolerance). }
203
    function Equals(const AOther: TVector2; const ATolerance: Single = SINGLE_TOLERANCE): Boolean; inline;
204

205
    { Calculates the distance between this vector and another vector.
206

207
      Parameters:
208
        AOther: the other vector.
209

210
      Returns:
211
        The distance between this vector and AOther.
212

213
      @bold(Note): If you only want to compare distances, you should use
214
      DistanceSquared instead, which is faster. }
215
    function Distance(const AOther: TVector2): Single; inline;
216

217
    { Calculates the squared distance between this vector and another vector.
218

219
      Parameters:
220
        AOther: the other vector.
221

222
      Returns:
223
        The squared distance between this vector and AOther. }
224
    function DistanceSquared(const AOther: TVector2): Single; inline;
225

226
    { Calculates the dot product between this vector and another vector.
227

228
      Parameters:
229
        AOther: the other vector.
230

231
      Returns:
232
        The dot product between this vector and AOther. }
233
    function Dot(const AOther: TVector2): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
234

235
    { Calculates the cross product between this vector and another vector.
236

237
      Parameters:
238
        AOther: the other vector.
239

240
      Returns:
241
        The cross product between this vector and AOther. }
242
    function Cross(const AOther: TVector2): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
243

244
    { Offsets this vector in a certain direction.
245

246
      Parameters:
247
        ADeltaX: the delta X direction.
248
        ADeltaY: the delta Y direction. }
249
    procedure Offset(const ADeltaX, ADeltaY: Single); overload; inline;
250

251
    { Offsets this vector in a certain direction.
252

253
      Parameters:
254
        ADelta: the delta.
255

256
      @bold(Note): this is equivalent to adding two vectors together. }
257
    procedure Offset(const ADelta: TVector2); overload; inline;
258

259
    { Calculates a normalized version of this vector.
260

261
      Returns:
262
        The normalized version of of this vector. That is, a vector in the same
263
        direction as A, but with a length of 1.
264

265
      @bold(Note): for a faster, less accurate version, use NormalizeFast.
266

267
      @bold(Note): Does not change this vector. To update this vector itself,
268
      use SetNormalized. }
269
    function Normalize: TVector2; inline;
270

271
    { Normalizes this vector. This is, keep the current direction, but set the
272
      length to 1.
273

274
      @bold(Note): The SIMD optimized versions of this method use an
275
      approximation, resulting in a very small error.
276

277
      @bold(Note): If you do not want to change this vector, but get a
278
      normalized version instead, then use Normalize. }
279
    procedure SetNormalized; inline;
280

281
    { Calculates a normalized version of this vector.
282

283
      Returns:
284
        The normalized version of of this vector. That is, a vector in the same
285
        direction as A, but with a length of 1.
286

287
      @bold(Note): this is an SIMD optimized version that uses an approximation,
288
      resulting in a small error. For an accurate version, use Normalize.
289

290
      @bold(Note): Does not change this vector. To update this vector itself,
291
      use SetNormalizedFast. }
292
    function NormalizeFast: TVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
293

294
    { Normalizes this vector. This is, keep the current direction, but set the
295
      length to 1.
296

297
      @bold(Note): this is an SIMD optimized version that uses an approximation,
298
      resulting in a small error. For an accurate version, use SetNormalized.
299

300
      @bold(Note): If you do not want to change this vector, but get a
301
      normalized version instead, then use NormalizeFast. }
302
    procedure SetNormalizedFast; {$IFDEF FM_INLINE}inline;{$ENDIF}
303

304
    { Calculates a vector pointing in the same direction as this vector.
305

306
      Parameters:
307
        I: the incident vector.
308
        NRef: the reference vector.
309

310
      Returns:
311
        A vector that points away from the surface as defined by its normal. If
312
        NRef.Dot(I) < 0 then it returns this vector, otherwise it returns the
313
        negative of this vector. }
314
    function FaceForward(const I, NRef: TVector2): TVector2; inline;
315

316
    { Calculates the reflection direction for this (incident) vector.
317

318
      Parameters:
319
        N: the normal vector. Should be normalized in order to achieve the desired
320
          result.
321

322
      Returns:
323
        The reflection direction calculated as Self - 2 * N.Dot(Self) * N. }
324
    function Reflect(const N: TVector2): TVector2; inline;
325

326
    { Calculates the refraction direction for this (incident) vector.
327

328
      Parameters:
329
        N: the normal vector. Should be normalized in order to achieve the
330
          desired result.
331
        Eta: the ratio of indices of refraction.
332

333
      Returns:
334
        The refraction vector.
335

336
      @bold(Note): This vector should be normalized in order to achieve the
337
      desired result.}
338
    function Refract(const N: TVector2; const Eta: Single): TVector2; inline;
339

340
    { Creates a vector with the same direction as this vector, but with the
341
      length limited, based on the desired maximum length.
342

343
      Parameters:
344
        AMaxLength: The desired maximum length of the vector.
345

346
      Returns:
347
        A length-limited version of this vector.
348

349
      @bold(Note): Does not change this vector. To update this vector itself,
350
      use SetLimit. }
351
    function Limit(const AMaxLength: Single): TVector2; inline;
352

353
    { Limits the length of this vector, based on the desired maximum length.
354

355
      Parameters:
356
        AMaxLength: The desired maximum length of this vector.
357

358
      @bold(Note): If you do not want to change this vector, but get a
359
      length-limited version instead, then use Limit. }
360
    procedure SetLimit(const AMaxLength: Single); inline;
361

362
    { Creates a vector with the same direction as this vector, but with the
363
      length limited, based on the desired squared maximum length.
364

365
      Parameters:
366
        AMaxLengthSquared: The desired squared maximum length of the vector.
367

368
      Returns:
369
        A length-limited version of this vector.
370

371
      @bold(Note): Does not change this vector. To update this vector itself,
372
      use SetLimitSquared. }
373
    function LimitSquared(const AMaxLengthSquared: Single): TVector2;
374

375
    { Limits the length of this vector, based on the desired squared maximum
376
      length.
377

378
      Parameters:
379
        AMaxLengthSquared: The desired squared maximum length of this vector.
380

381
      @bold(Note): If you do not want to change this vector, but get a
382
      length-limited version instead, then use LimitSquared. }
383
    procedure SetLimitSquared(const AMaxLengthSquared: Single); inline;
384

385
    { Creates a vector with the same direction as this vector, but with the
386
      length clamped between a minimim and maximum length.
387

388
      Parameters:
389
        AMinLength: The minimum length of the vector.
390
        AMaxLength: The maximum length of the vector.
391

392
      Returns:
393
        A length-clamped version of this vector.
394

395
      @bold(Note): Does not change this vector. To update this vector itself,
396
      use SetClamped. }
397
    function Clamp(const AMinLength, AMaxLength: Single): TVector2;
398

399
    { Clamps the length of this vector between a minimim and maximum length.
400

401
      Parameters:
402
        AMinLength: The minimum length of this vector.
403
        AMaxLength: The maximum length of this vector.
404

405
      @bold(Note): If you do not want to change this vector, but get a
406
      length-clamped version instead, then use Clamp. }
407
    procedure SetClamped(const AMinLength, AMaxLength: Single); inline;
408

409
    { Creates a vector by rotating this vector counter-clockwise.
410

411
      AParameters:
412
        ARadians: the rotation angle in radians, counter-clockwise assuming the
413
          Y-axis points up.
414

415
      Returns:
416
        A rotated version version of this vector.
417

418
      @bold(Note): Does not change this vector. To update this vector itself,
419
      use SetRotated. }
420
    function Rotate(const ARadians: Single): TVector2;
421

422
    { Rotates this vector counter-clockwise.
423

424
      AParameters:
425
        ARadians: the rotation angle in radians, counter-clockwise assuming the
426
          Y-axis points up.
427

428
      @bold(Note): If you do not want to change this vector, but get a
429
      rotated version instead, then use Rotate. }
430
    procedure SetRotated(const ARadians: Single); inline;
431

432
    { Creates a vector by rotating this vector 90 degrees counter-clockwise.
433

434
      Returns:
435
        A rotated version version of this vector.
436

437
      @bold(Note): Does not change this vector. To update this vector itself,
438
      use SetRotated90CCW. }
439
    function Rotate90CCW: TVector2;
440

441
    { Rotates this vector 90 degrees counter-clockwise.
442

443
      @bold(Note): If you do not want to change this vector, but get a
444
      rotated version instead, then use Rotate90CCW. }
445
    procedure SetRotated90CCW; inline;
446

447
    { Creates a vector by rotating this vector 90 degrees clockwise.
448

449
      Returns:
450
        A rotated version version of this vector.
451

452
      @bold(Note): Does not change this vector. To update this vector itself,
453
      use SetRotated90CW. }
454
    function Rotate90CW: TVector2;
455

456
    { Rotates this vector 90 degrees clockwise.
457

458
      @bold(Note): If you do not want to change this vector, but get a
459
      rotated version instead, then use Rotate90CW. }
460
    procedure SetRotated90CW; inline;
461

462
    { Calculates the angle in radians to rotate this vector/point to a target
463
      vector. Angles are towards the positive Y-axis (counter-clockwise).
464

465
      Parameters:
466
        ATarget: the target vector.
467

468
      Returns:
469
        The angle in radians to the target vector, in the range -Pi to Pi. }
470
    function AngleTo(const ATarget: TVector2): Single;
471

472
    { Linearly interpolates between this vector and a target vector.
473

474
      Parameters:
475
        ATarget: the target vector.
476
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
477

478
      Returns:
479
        The interpolation result vector.
480

481
      @bold(Note): Does not change this vector. To update this vector itself,
482
      use SetLerp. }
483
    function Lerp(const ATarget: TVector2; const AAlpha: Single): TVector2; inline;
484

485
    { Linearly interpolates between this vector and a target vector and stores
486
      the result in this vector.
487

488
      Parameters:
489
        ATarget: the target vector.
490
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
491

492
      @bold(Note): If you do not want to change this vector, but get an
493
      interpolated version instead, then use Lerp. }
494
    procedure SetLerp(const ATarget: TVector2; const AAlpha: Single); inline;
495

496
    { Whether the vector is normalized (within a small margin of error).
497

498
      Returns:
499
        True if the length of the vector is (very close to) 1.0 }
500
    function IsNormalized: Boolean; overload; inline;
501

502
    { Whether the vector is normalized within a given margin of error.
503

504
      Parameters:
505
        AErrorMargin: the allowed margin of error.
506

507
      Returns:
508
        True if the squared length of the vector is 1.0 within the margin of
509
        error. }
510
    function IsNormalized(const AErrorMargin: Single): Boolean; overload;
511

512
    { Whether this is a zero vector.
513

514
      Returns:
515
        True if X and Y are exactly 0.0 }
516
    function IsZero: Boolean; overload; inline;
517

518
    { Whether this is a zero vector within a given margin of error.
519

520
      Parameters:
521
        AErrorMargin: the allowed margin of error.
522

523
      Returns:
524
        True if the squared length is smaller then the margin of error. }
525
    function IsZero(const AErrorMargin: Single): Boolean; overload;
526

527
    { Whether this vector has a similar direction compared to another vector.
528

529
      Parameters:
530
        AOther: the other vector.
531

532
      Returns:
533
        True if the normalized dot product is greater than 0. }
534
    function HasSameDirection(const AOther: TVector2): Boolean; inline;
535

536
    { Whether this vector has an opposite direction compared to another vector.
537

538
      Parameters:
539
        AOther: the other vector.
540

541
      Returns:
542
        True if the normalized dot product is less than 0. }
543
    function HasOppositeDirection(const AOther: TVector2): Boolean; inline;
544

545
    { Whether this vector runs parallel to another vector (either in the same
546
      or the opposite direction).
547

548
      Parameters:
549
        AOther: the other vector.
550
        ATolerance: (optional) tolerance. If not specified, a small tolerance
551
          is used.
552

553
      Returns:
554
        True if this vector runs parallel to AOther (within the given tolerance)
555

556
      @bold(Note): every vector is considered to run parallel to a zero vector. }
557
    function IsParallel(const AOther: TVector2; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
558

559
    { Whether this vector is collinear with another vector. Two vectors are
560
      collinear if they run parallel to each other and point in the same
561
      direction.
562

563
      Parameters:
564
        AOther: the other vector.
565
        ATolerance: (optional) tolerance. If not specified, a small tolerance
566
          is used.
567

568
      Returns:
569
        True if this vector is collinear to AOther (within the given tolerance) }
570
    function IsCollinear(const AOther: TVector2; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
571

572
    { Whether this vector is opposite collinear with another vector. Two vectors
573
      are opposite collinear if they run parallel to each other and point in
574
      opposite directions.
575

576
      Parameters:
577
        AOther: the other vector.
578
        ATolerance: (optional) tolerance. If not specified, a small tolerance
579
          is used.
580

581
      Returns:
582
        True if this vector is opposite collinear to AOther (within the given
583
        tolerance) }
584
    function IsCollinearOpposite(const AOther: TVector2; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
585

586
    { Whether this vector is perpendicular to another vector.
587

588
      Parameters:
589
        AOther: the other vector.
590
        ATolerance: (optional) tolerance. If not specified, a small tolerance
591
          is used.
592

593
      Returns:
594
        True if this vector is perpendicular to AOther. That is, if the dot
595
        product is 0 (within the given tolerance) }
596
    function IsPerpendicular(const AOther: TVector2; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
597

598
    { Returns the components of the vector.
599
      This is identical to accessing the C-field, but this property can be used
600
      as a default array property.
601

602
      Parameters:
603
        AIndex: index of the component to return (0 or 1). Range is checked
604
          with an assertion. }
605
    property Components[const AIndex: Integer]: Single read GetComponent write SetComponent; default;
606

607
    { The euclidean length of this vector.
608

609
      @bold(Note): If you only want to compare lengths of vectors, you should
610
      use LengthSquared instead, which is faster.
611

612
      @bold(Note): You can also set the length of the vector. In that case, it
613
      will keep the current direction. }
614
    property Length: Single read GetLength write SetLength;
615

616
    { The squared length of the vector.
617

618
      @bold(Note): This property is faster than Length because it avoids
619
      calculating a square root. It is useful for comparing lengths instead of
620
      calculating actual lengths.
621

622
      @bold(Note): You can also set the squared length of the vector. In that
623
      case, it will keep the current direction. }
624
    property LengthSquared: Single read GetLengthSquared write SetLengthSquared;
625

626
    { The angle in radians of this vector/point relative to the X-axis. Angles
627
      are towards the positive Y-axis (counter-clockwise).
628

629
      When getting the angle, the result will be between -Pi and Pi. }
630
    property Angle: Single read GetAngle write SetAngle;
631
  public
632
    case Byte of
633
      { X and Y components of the vector. Aliases for C[0] and C[1]. }
634
      0: (X, Y: Single);
635

636
      { Red and Green components of the vector. Aliases for C[0] and C[1]. }
637
      1: (R, G: Single);
638

639
      { S and T components of the vector. Aliases for C[0] and C[1]. }
640
      2: (S, T: Single);
641

642
      { The two components of the vector. }
643
      3: (C: array [0..1] of Single);
644
  end;
645
  PVector2 = ^TVector2;
646

647
type
648
  { A 3-dimensional vector. Can be used for a variety of purposes:
649
    * To represent points or vectors in 3D space, using the X, Y and Z fields.
650
    * To represent colors (using the R, G and B fields, which are just aliases
651
      for X, Y and Z)
652
    * To represent texture coordinates (S, T and P, again just aliases for X, Y
653
      and Z).
654
    * To group 3 arbitrary values together in an array (C[0]..C[2], also just
655
      aliases for X, Y and Z)
656

657
    @bold(Note): when possible, use TVector4 instead of TVector3, since TVector4
658
    has better hardware support. Operations on TVector4 types are usually faster
659
    than operations on TVector3 types.
660

661
    TVector3 is compatible with TPoint3D in the Delphi RTL. You can typecast
662
    between these two types or implicitly convert from one to the other through
663
    assignment (eg. MyVector3 := MyPoint3D). }
664
  TVector3 = record
665
  {$REGION 'Internal Declarations'}
666
  private
667
    function GetComponent(const AIndex: Integer): Single; inline;
668
    procedure SetComponent(const AIndex: Integer; const Value: Single); inline;
669
    function GetLength: Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
670
    procedure SetLength(const AValue: Single); inline;
671
    function GetLengthSquared: Single; inline;
672
    procedure SetLengthSquared(const AValue: Single); inline;
673
  {$ENDREGION 'Internal Declarations'}
674
  public
675
    { Sets the three elements (X, Y and Z) to 0. }
676
    procedure Init; overload; inline;
677

678
    { Sets the three elements (X, Y and Z) to A.
679

680
      Parameters:
681
        A: the value to set the three elements to. }
682
    procedure Init(const A: Single); overload; inline;
683

684
    { Sets the three elements (X, Y and Z) to A1, A2 and A3 respectively.
685

686
      Parameters:
687
        A1: the value to set the first element to.
688
        A2: the value to set the second element to.
689
        A3: the value to set the third element to. }
690
    procedure Init(const A1, A2, A3: Single); overload; inline;
691

692
    { Sets the first two elements from a 2D vector, and the third element from
693
      a scalar.
694

695
      Parameters:
696
        A1: the vector to use for the first two elements.
697
        A2: the value to set the third element to. }
698
    procedure Init(const A1: TVector2; const A2: Single); overload; inline;
699

700
    { Sets the first element from a scaler, and the last two elements from a
701
      2D vector.
702

703
      Parameters:
704
        A1: the value to set the first element to.
705
        A2: the vector to use for the last two elements. }
706
    procedure Init(const A1: Single; const A2: TVector2); overload; inline;
707

708
    { Implicitly converts a TPoint3D to a TVector3. }
709
    class operator Implicit(const A: TPoint3D): TVector3; inline;
710

711
    { Implicitly converts a TVector3 to a TPoint3D. }
712
    class operator Implicit(const A: TVector3): TPoint3D; inline;
713

714
    { Checks two vectors for equality.
715

716
      Returns:
717
        True if the two vectors match each other exactly. }
718
    class operator Equal(const A, B: TVector3): Boolean; inline;
719

720
    { Checks two vectors for inequality.
721

722
      Returns:
723
        True if the two vectors are not equal. }
724
    class operator NotEqual(const A, B: TVector3): Boolean; inline;
725

726
    { Negates a vector.
727

728
      Returns:
729
        The negative value of a vector (eg. (-A.X, -A.Y, -A.Z)) }
730
    class operator Negative(const A: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
731

732
    { Adds a scalar value to a vector.
733

734
      Returns:
735
        (A.X + B, A.Y + B, A.Z + B) }
736
    class operator Add(const A: TVector3; const B: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
737

738
    { Adds a vector to a scalar value.
739

740
      Returns:
741
        (A + B.X, A + B.Y, A + B.Z) }
742
    class operator Add(const A: Single; const B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
743

744
    { Adds two vectors.
745

746
      Returns:
747
        (A.X + B.X, A.Y + B.Y, A.Z + B.Z) }
748
    class operator Add(const A, B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
749

750
    { Subtracts a scalar value from a vector.
751

752
      Returns:
753
        (A.X - B, A.Y - B, A.Z - B) }
754
    class operator Subtract(const A: TVector3; const B: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
755

756
    { Subtracts a vector from a scalar value.
757

758
      Returns:
759
        (A - B.X, A - B.Y, A - B.Z) }
760
    class operator Subtract(const A: Single; const B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
761

762
    { Subtracts two vectors.
763

764
      Returns:
765
        (A.X - B.X, A.Y - B.Y, A.Z - B.Z) }
766
    class operator Subtract(const A, B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
767

768
    { Multiplies a vector with a scalar value.
769

770
      Returns:
771
        (A.X * B, A.Y * B, A.Z * B) }
772
    class operator Multiply(const A: TVector3; const B: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
773

774
    { Multiplies a scalar value with a vector.
775

776
      Returns:
777
        (A * B.X, A * B.Y, A * B.Z) }
778
    class operator Multiply(const A: Single; const B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
779

780
    { Multiplies two vectors component-wise.
781
      To calculate a dot or cross product instead, use the Dot or Cross function.
782

783
      Returns:
784
        (A.X * B.X, A.Y * B.Y, A.Z * B.Z) }
785
    class operator Multiply(const A, B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
786

787
    { Divides a vector by a scalar value.
788

789
      Returns:
790
        (A.X / B, A.Y / B, A.Z / B) }
791
    class operator Divide(const A: TVector3; const B: Single): TVector3; inline;
792

793
    { Divides a scalar value by a vector.
794

795
      Returns:
796
        (A / B.X, A / B.Y, A / B.Z) }
797
    class operator Divide(const A: Single; const B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
798

799
    { Divides two vectors component-wise.
800

801
      Returns:
802
        (A.X / B.X, A.Y / B.Y, A.Z / B.Z) }
803
    class operator Divide(const A, B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
804

805
    { Whether this vector equals another vector, within a certain tolerance.
806

807
      Parameters:
808
        AOther: the other vector.
809
        ATolerance: (optional) tolerance. If not specified, a small tolerance
810
          is used.
811

812
      Returns:
813
        True if both vectors are equal (within the given tolerance). }
814
    function Equals(const AOther: TVector3; const ATolerance: Single = SINGLE_TOLERANCE): Boolean; inline;
815

816
    { Calculates the distance between this vector and another vector.
817

818
      Parameters:
819
        AOther: the other vector.
820

821
      Returns:
822
        The distance between this vector and AOther.
823

824
      @bold(Note): If you only want to compare distances, you should use
825
      DistanceSquared instead, which is faster. }
826
    function Distance(const AOther: TVector3): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
827

828
    { Calculates the squared distance between this vector and another vector.
829

830
      Parameters:
831
        AOther: the other vector.
832

833
      Returns:
834
        The squared distance between this vector and AOther. }
835
    function DistanceSquared(const AOther: TVector3): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
836

837
    { Calculates the dot product between this vector and another vector.
838

839
      Parameters:
840
        AOther: the other vector.
841

842
      Returns:
843
        The dot product between this vector and AOther. }
844
    function Dot(const AOther: TVector3): Single; inline;
845

846
    { Calculates the cross product between this vector and another vector.
847

848
      Parameters:
849
        AOther: the other vector.
850

851
      Returns:
852
        The cross product between this vector and AOther. }
853
    function Cross(const AOther: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
854

855
    { Offsets this vector in a certain direction.
856

857
      Parameters:
858
        ADeltaX: the delta X direction.
859
        ADeltaY: the delta Y direction.
860
        ADeltaZ: the delta Z direction. }
861
    procedure Offset(const ADeltaX, ADeltaY, ADeltaZ: Single); overload; inline;
862

863
    { Offsets this vector in a certain direction.
864

865
      Parameters:
866
        ADelta: the delta.
867

868
      @bold(Note): this is equivalent to adding two vectors together. }
869
    procedure Offset(const ADelta: TVector3); overload; inline;
870

871

872
    { Calculates a normalized version of this vector.
873

874
      Returns:
875
        The normalized version of of this vector. That is, a vector in the same
876
        direction as A, but with a length of 1.
877

878
      @bold(Note): for a faster, less accurate version, use NormalizeFast.
879

880
      @bold(Note): Does not change this vector. To update this vector itself,
881
      use SetNormalized. }
882
    function Normalize: TVector3; inline;
883

884
    { Normalizes this vector. This is, keep the current direction, but set the
885
      length to 1.
886

887
      @bold(Note): The SIMD optimized versions of this method use an
888
      approximation, resulting in a very small error.
889

890
      @bold(Note): If you do not want to change this vector, but get a
891
      normalized version instead, then use Normalize. }
892
    procedure SetNormalized; inline;
893

894
    { Calculates a normalized version of this vector.
895

896
      Returns:
897
        The normalized version of of this vector. That is, a vector in the same
898
        direction as A, but with a length of 1.
899

900
      @bold(Note): this is an SIMD optimized version that uses an approximation,
901
      resulting in a small error. For an accurate version, use Normalize.
902

903
      @bold(Note): Does not change this vector. To update this vector itself,
904
      use SetNormalizedFast. }
905
    function NormalizeFast: TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
906

907
    { Normalizes this vector. This is, keep the current direction, but set the
908
      length to 1.
909

910
      @bold(Note): this is an SIMD optimized version that uses an approximation,
911
      resulting in a small error. For an accurate version, use SetNormalized.
912

913
      @bold(Note): If you do not want to change this vector, but get a
914
      normalized version instead, then use NormalizeFast. }
915
    procedure SetNormalizedFast; {$IFDEF FM_INLINE}inline;{$ENDIF}
916

917
    { Calculates a vector pointing in the same direction as this vector.
918

919
      Parameters:
920
        I: the incident vector.
921
        NRef: the reference vector.
922

923
      Returns:
924
        A vector that points away from the surface as defined by its normal. If
925
        NRef.Dot(I) < 0 then it returns this vector, otherwise it returns the
926
        negative of this vector. }
927
    function FaceForward(const I, NRef: TVector3): TVector3; inline;
928

929
    { Calculates the reflection direction for this (incident) vector.
930

931
      Parameters:
932
        N: the normal vector. Should be normalized in order to achieve the desired
933
          result.
934

935
      Returns:
936
        The reflection direction calculated as Self - 2 * N.Dot(Self) * N. }
937
    function Reflect(const N: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
938

939
    { Calculates the refraction direction for this (incident) vector.
940

941
      Parameters:
942
        N: the normal vector. Should be normalized in order to achieve the
943
          desired result.
944
        Eta: the ratio of indices of refraction.
945

946
      Returns:
947
        The refraction vector.
948

949
      @bold(Note): This vector should be normalized in order to achieve the
950
      desired result.}
951
    function Refract(const N: TVector3; const Eta: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
952

953
    { Creates a vector with the same direction as this vector, but with the
954
      length limited, based on the desired maximum length.
955

956
      Parameters:
957
        AMaxLength: The desired maximum length of the vector.
958

959
      Returns:
960
        A length-limited version of this vector.
961

962
      @bold(Note): Does not change this vector. To update this vector itself,
963
      use SetLimit. }
964
    function Limit(const AMaxLength: Single): TVector3; inline;
965

966
    { Limits the length of this vector, based on the desired maximum length.
967

968
      Parameters:
969
        AMaxLength: The desired maximum length of this vector.
970

971
      @bold(Note): If you do not want to change this vector, but get a
972
      length-limited version instead, then use Limit. }
973
    procedure SetLimit(const AMaxLength: Single); inline;
974

975
    { Creates a vector with the same direction as this vector, but with the
976
      length limited, based on the desired squared maximum length.
977

978
      Parameters:
979
        AMaxLengthSquared: The desired squared maximum length of the vector.
980

981
      Returns:
982
        A length-limited version of this vector.
983

984
      @bold(Note): Does not change this vector. To update this vector itself,
985
      use SetLimitSquared. }
986
    function LimitSquared(const AMaxLengthSquared: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
987

988
    { Limits the length of this vector, based on the desired squared maximum
989
      length.
990

991
      Parameters:
992
        AMaxLengthSquared: The desired squared maximum length of this vector.
993

994
      @bold(Note): If you do not want to change this vector, but get a
995
      length-limited version instead, then use LimitSquared. }
996
    procedure SetLimitSquared(const AMaxLengthSquared: Single);
997

998
    { Creates a vector with the same direction as this vector, but with the
999
      length clamped between a minimim and maximum length.
1000

1001
      Parameters:
1002
        AMinLength: The minimum length of the vector.
1003
        AMaxLength: The maximum length of the vector.
1004

1005
      Returns:
1006
        A length-clamped version of this vector.
1007

1008
      @bold(Note): Does not change this vector. To update this vector itself,
1009
      use SetClamped. }
1010
    function Clamp(const AMinLength, AMaxLength: Single): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
1011

1012
    { Clamps the length of this vector between a minimim and maximum length.
1013

1014
      Parameters:
1015
        AMinLength: The minimum length of this vector.
1016
        AMaxLength: The maximum length of this vector.
1017

1018
      @bold(Note): If you do not want to change this vector, but get a
1019
      length-clamped version instead, then use Clamp. }
1020
    procedure SetClamped(const AMinLength, AMaxLength: Single);
1021

1022
    { Linearly interpolates between this vector and a target vector.
1023

1024
      Parameters:
1025
        ATarget: the target vector.
1026
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
1027

1028
      Returns:
1029
        The interpolation result vector.
1030

1031
      @bold(Note): Does not change this vector. To update this vector itself,
1032
      use SetLerp. }
1033
    function Lerp(const ATarget: TVector3; const AAlpha: Single): TVector3; inline;
1034

1035
    { Linearly interpolates between this vector and a target vector and stores
1036
      the result in this vector.
1037

1038
      Parameters:
1039
        ATarget: the target vector.
1040
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
1041

1042
      @bold(Note): If you do not want to change this vector, but get an
1043
      interpolated version instead, then use Lerp. }
1044
    procedure SetLerp(const ATarget: TVector3; const AAlpha: Single); inline;
1045

1046
    { Whether the vector is normalized (within a small margin of error).
1047

1048
      Returns:
1049
        True if the length of the vector is (very close to) 1.0 }
1050
    function IsNormalized: Boolean; overload; inline;
1051

1052
    { Whether the vector is normalized within a given margin of error.
1053

1054
      Parameters:
1055
        AErrorMargin: the allowed margin of error.
1056

1057
      Returns:
1058
        True if the squared length of the vector is 1.0 within the margin of
1059
        error. }
1060
    function IsNormalized(const AErrorMargin: Single): Boolean; overload;
1061

1062
    { Whether this is a zero vector.
1063

1064
      Returns:
1065
        True if X, Y and Z are exactly 0.0 }
1066
    function IsZero: Boolean; overload; inline;
1067

1068
    { Whether this is a zero vector within a given margin of error.
1069

1070
      Parameters:
1071
        AErrorMargin: the allowed margin of error.
1072

1073
      Returns:
1074
        True if the squared length is smaller then the margin of error. }
1075
    function IsZero(const AErrorMargin: Single): Boolean; overload;
1076

1077
    { Whether this vector has a similar direction compared to another vector.
1078

1079
      Parameters:
1080
        AOther: the other vector.
1081

1082
      Returns:
1083
        True if the normalized dot product is greater than 0. }
1084
    function HasSameDirection(const AOther: TVector3): Boolean; inline;
1085

1086
    { Whether this vector has an opposite direction compared to another vector.
1087

1088
      Parameters:
1089
        AOther: the other vector.
1090

1091
      Returns:
1092
        True if the normalized dot product is less than 0. }
1093
    function HasOppositeDirection(const AOther: TVector3): Boolean; inline;
1094

1095
    { Whether this vector runs parallel to another vector (either in the same
1096
      or the opposite direction).
1097

1098
      Parameters:
1099
        AOther: the other vector.
1100
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1101
          is used.
1102

1103
      Returns:
1104
        True if this vector runs parallel to AOther (within the given tolerance) }
1105
    function IsParallel(const AOther: TVector3; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1106

1107
    { Whether this vector is collinear with another vector. Two vectors are
1108
      collinear if they run parallel to each other and point in the same
1109
      direction.
1110

1111
      Parameters:
1112
        AOther: the other vector.
1113
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1114
          is used.
1115

1116
      Returns:
1117
        True if this vector is collinear to AOther (within the given tolerance) }
1118
    function IsCollinear(const AOther: TVector3; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1119

1120
    { Whether this vector is opposite collinear with another vector. Two vectors
1121
      are opposite collinear if they run parallel to each other and point in
1122
      opposite directions.
1123

1124
      Parameters:
1125
        AOther: the other vector.
1126
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1127
          is used.
1128

1129
      Returns:
1130
        True if this vector is opposite collinear to AOther (within the given
1131
        tolerance) }
1132
    function IsCollinearOpposite(const AOther: TVector3; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1133

1134
    { Whether this vector is perpendicular to another vector.
1135

1136
      Parameters:
1137
        AOther: the other vector.
1138
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1139
          is used.
1140

1141
      Returns:
1142
        True if this vector is perpendicular to AOther. That is, if the dot
1143
        product is 0 (within the given tolerance) }
1144
    function IsPerpendicular(const AOther: TVector3; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1145

1146
    { Returns the components of the vector.
1147
      This is identical to accessing the C-field, but this property can be used
1148
      as a default array property.
1149

1150
      Parameters:
1151
        AIndex: index of the component to return (0-2). Range is checked
1152
          with an assertion. }
1153
    property Components[const AIndex: Integer]: Single read GetComponent write SetComponent; default;
1154

1155
    { The euclidean length of this vector.
1156

1157
      @bold(Note): If you only want to compare lengths of vectors, you should
1158
      use LengthSquared instead, which is faster.
1159

1160
      @bold(Note): You can also set the length of the vector. In that case, it
1161
      will keep the current direction. }
1162
    property Length: Single read GetLength write SetLength;
1163

1164
    { The squared length of the vector.
1165

1166
      @bold(Note): This property is faster than Length because it avoids
1167
      calculating a square root. It is useful for comparing lengths instead of
1168
      calculating actual lengths.
1169

1170
      @bold(Note): You can also set the squared length of the vector. In that
1171
      case, it will keep the current direction. }
1172
    property LengthSquared: Single read GetLengthSquared write SetLengthSquared;
1173
  public
1174
    case Byte of
1175
      { X, Y and Z components of the vector. Aliases for C[0], C[1] and C[2]. }
1176
      0: (X, Y, Z: Single);
1177

1178
      { Red, Green and Blue components of the vector. Aliases for C[0], C[1]
1179
        and C[2]. }
1180
      1: (R, G, B: Single);
1181

1182
      { S, T and P components of the vector. Aliases for C[0], C[1] and C[2]. }
1183
      2: (S, T, P: Single);
1184

1185
      { The three components of the vector. }
1186
      3: (C: array [0..2] of Single);
1187
  end;
1188
  PVector3 = ^TVector3;
1189

1190
type
1191
  { A 4-dimensional vector. Can be used for a variety of purposes:
1192
    * To represent points or vectors in 4D space, using the X, Y, Z and W
1193
      fields.
1194
    * To represent colors with alpha channel information (using the R, G, B and
1195
      A fields, which are just aliases for X, Y, Z and W)
1196
    * To represent texture coordinates (S, T, P and Q, again just aliases for X,
1197
      Y, Z and W).
1198
    * To group 4 arbitrary values together in an array (C[0]..C[3], also just
1199
      aliases for X, Y, Z and W)
1200

1201
    TVector4 is compatible with TVector3D in the Delphi RTL. You can typecast
1202
    between these two types or implicitly convert from one to the other through
1203
    assignment (eg. MyVector4 := MyPoint3D). }
1204
  TVector4 = record
1205
  {$REGION 'Internal Declarations'}
1206
  private
1207
    function GetComponent(const AIndex: Integer): Single; inline;
1208
    procedure SetComponent(const AIndex: Integer; const Value: Single); inline;
1209
    function GetLength: Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
1210
    procedure SetLength(const AValue: Single); inline;
1211
    function GetLengthSquared: Single; inline;
1212
    procedure SetLengthSquared(const AValue: Single); inline;
1213
  {$ENDREGION 'Internal Declarations'}
1214
  public
1215
    { Sets the four elements (X, Y, Z and W) to 0. }
1216
    procedure Init; overload; inline;
1217

1218
    { Sets the four elements (X, Y, Z and W) to A.
1219

1220
      Parameters:
1221
        A: the value to set the three elements to. }
1222
    procedure Init(const A: Single); overload; inline;
1223

1224
    { Sets the four elements (X, Y, Z and W) to A1, A2, A3 and A4 respectively.
1225

1226
      Parameters:
1227
        A1: the value to set the first element to.
1228
        A2: the value to set the second element to.
1229
        A3: the value to set the third element to.
1230
        A4: the value to set the fourth element to. }
1231
    procedure Init(const A1, A2, A3, A4: Single); overload; inline;
1232

1233
    { Sets the first two elements from a 2D vector, and the last two elements
1234
      from two scalars.
1235

1236
      Parameters:
1237
        A1: the vector to use for the first two elements.
1238
        A2: the value to set the third element to.
1239
        A3: the value to set the fourth element to. }
1240
    procedure Init(const A1: TVector2; const A2, A3: Single); overload; inline;
1241

1242
    { Sets the first and last elements from two scalars, and the middle two
1243
      elements from a 2D vector.
1244

1245
      Parameters:
1246
        A1: the value to set the first element to.
1247
        A2: the vector to use for the second and third elements.
1248
        A3: the value to set the fourth element to. }
1249
    procedure Init(const A1: Single; const A2: TVector2; const A3: Single); overload; inline;
1250

1251
    { Sets the first two elements from two scalars and the last two elements
1252
      from a 2D vector.
1253

1254
      Parameters:
1255
        A1: the value to set the first element to.
1256
        A2: the value to set the second element to.
1257
        A3: the vector to use for the last two elements. }
1258
    procedure Init(const A1, A2: Single; const A3: TVector2); overload; inline;
1259

1260
    { Sets the first two elements and last two elements from two 2D vectors.
1261

1262
      Parameters:
1263
        A1: the vector to use for the first two elements.
1264
        A2: the vector to use for the last two elements. }
1265
    procedure Init(const A1, A2: TVector2); overload; inline;
1266

1267
    { Sets the first three elements from a 3D vector, and the fourth element
1268
      from a scalar.
1269

1270
      Parameters:
1271
        A1: the vector to use for the first three elements.
1272
        A2: the value to set the fourth element to. }
1273
    procedure Init(const A1: TVector3; const A2: Single); overload; inline;
1274

1275
    { Sets the first element from a scaler, and the last three elements from a
1276
      3D vector.
1277

1278
      Parameters:
1279
        A1: the value to set the first element to.
1280
        A2: the vector to use for the last three elements. }
1281
    procedure Init(const A1: Single; const A2: TVector3); overload; inline;
1282

1283
    { Implicitly converts a TVector3D to a TVector4. }
1284
    class operator Implicit(const A: TVector3D): TVector4; inline;
1285

1286
    { Implicitly converts a TVector4 to a TVector3D. }
1287
    class operator Implicit(const A: TVector4): TVector3D; inline;
1288

1289
    { Checks two vectors for equality.
1290

1291
      Returns:
1292
        True if the two vectors match each other exactly. }
1293
    class operator Equal(const A, B: TVector4): Boolean; inline;
1294

1295
    { Checks two vectors for inequality.
1296

1297
      Returns:
1298
        True if the two vectors are not equal. }
1299
    class operator NotEqual(const A, B: TVector4): Boolean; inline;
1300

1301
    { Negates a vector.
1302

1303
      Returns:
1304
        The negative value of a vector (eg. (-A.X, -A.Y, -A.Z, -A.W)) }
1305
    class operator Negative(const A: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1306

1307
    { Adds a scalar value to a vector.
1308

1309
      Returns:
1310
        (A.X + B, A.Y + B, A.Z + B, A.W + B) }
1311
    class operator Add(const A: TVector4; const B: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1312

1313
    { Adds a vector to a scalar value.
1314

1315
      Returns:
1316
        (A + B.X, A + B.Y, A + B.Z, A + B.W) }
1317
    class operator Add(const A: Single; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1318

1319
    { Adds two vectors.
1320

1321
      Returns:
1322
        (A.X + B.X, A.Y + B.Y, A.Z + B.Z, A.W + B.W) }
1323
    class operator Add(const A, B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1324

1325
    { Subtracts a scalar value from a vector.
1326

1327
      Returns:
1328
        (A.X - B, A.Y - B, A.Z - B, A.W - B) }
1329
    class operator Subtract(const A: TVector4; const B: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1330

1331
    { Subtracts a vector from a scalar value.
1332

1333
      Returns:
1334
        (A - B.X, A - B.Y, A - B.Z, A - B.W) }
1335
    class operator Subtract(const A: Single; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1336

1337
    { Subtracts two vectors.
1338

1339
      Returns:
1340
        (A.X - B.X, A.Y - B.Y, A.Z - B.Z, A.W - B.W) }
1341
    class operator Subtract(const A, B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1342

1343
    { Multiplies a vector with a scalar value.
1344

1345
      Returns:
1346
        (A.X * B, A.Y * B, A.Z * B, A.W * B) }
1347
    class operator Multiply(const A: TVector4; const B: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1348

1349
    { Multiplies a scalar value with a vector.
1350

1351
      Returns:
1352
        (A * B.X, A * B.Y, A * B.Z, A * B.W) }
1353
    class operator Multiply(const A: Single; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1354

1355
    { Multiplies two vectors component-wise.
1356
      To calculate a dot product instead, use the Dot function.
1357

1358
      Returns:
1359
        (A.X * B.X, A.Y * B.Y, A.Z * B.Z, A.W * B.W) }
1360
    class operator Multiply(const A, B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1361

1362
    { Divides a vector by a scalar value.
1363

1364
      Returns:
1365
        (A.X / B, A.Y / B, A.Z / B, A.W / B) }
1366
    class operator Divide(const A: TVector4; const B: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1367

1368
    { Divides a scalar value by a vector.
1369

1370
      Returns:
1371
        (A / B.X, A / B.Y, A / B.Z, A / B.W) }
1372
    class operator Divide(const A: Single; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1373

1374
    { Divides two vectors component-wise.
1375

1376
      Returns:
1377
        (A.X / B.X, A.Y / B.Y, A.Z / B.Z, A.W / B.W) }
1378
    class operator Divide(const A, B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1379

1380
    { Whether this vector equals another vector, within a certain tolerance.
1381

1382
      Parameters:
1383
        AOther: the other vector.
1384
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1385
          is used.
1386

1387
      Returns:
1388
        True if both vectors are equal (within the given tolerance). }
1389
    function Equals(const AOther: TVector4; const ATolerance: Single = SINGLE_TOLERANCE): Boolean; inline;
1390

1391
    { Calculates the distance between this vector and another vector.
1392

1393
      Parameters:
1394
        AOther: the other vector.
1395

1396
      Returns:
1397
        The distance between this vector and AOther.
1398

1399
      @bold(Note): If you only want to compare distances, you should use
1400
      DistanceSquared instead, which is faster. }
1401
    function Distance(const AOther: TVector4): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
1402

1403
    { Calculates the squared distance between this vector and another vector.
1404

1405
      Parameters:
1406
        AOther: the other vector.
1407

1408
      Returns:
1409
        The squared distance between this vector and AOther. }
1410
    function DistanceSquared(const AOther: TVector4): Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
1411

1412
    { Calculates the dot product between this vector and another vector.
1413

1414
      Parameters:
1415
        AOther: the other vector.
1416

1417
      Returns:
1418
        The dot product between this vector and AOther. }
1419
    function Dot(const AOther: TVector4): Single; inline;
1420

1421
    { Offsets this vector in a certain direction.
1422

1423
      Parameters:
1424
        ADeltaX: the delta X direction.
1425
        ADeltaY: the delta Y direction.
1426
        ADeltaZ: the delta Z direction.
1427
        ADeltaW: the delta W direction. }
1428
    procedure Offset(const ADeltaX, ADeltaY, ADeltaZ, ADeltaW: Single); overload; inline;
1429

1430
    { Offsets this vector in a certain direction.
1431

1432
      Parameters:
1433
        ADelta: the delta.
1434

1435
      @bold(Note): this is equivalent to adding two vectors together. }
1436
    procedure Offset(const ADelta: TVector4); overload; inline;
1437

1438

1439
    { Calculates a normalized version of this vector.
1440

1441
      Returns:
1442
        The normalized version of of this vector. That is, a vector in the same
1443
        direction as A, but with a length of 1.
1444

1445
      @bold(Note): for a faster, less accurate version, use NormalizeFast.
1446

1447
      @bold(Note): Does not change this vector. To update this vector itself,
1448
      use SetNormalized. }
1449
    function Normalize: TVector4; inline;
1450

1451
    { Normalizes this vector. This is, keep the current direction, but set the
1452
      length to 1.
1453

1454
      @bold(Note): The SIMD optimized versions of this method use an
1455
      approximation, resulting in a very small error.
1456

1457
      @bold(Note): If you do not want to change this vector, but get a
1458
      normalized version instead, then use Normalize. }
1459
    procedure SetNormalized; inline;
1460

1461
    { Calculates a normalized version of this vector.
1462

1463
      Returns:
1464
        The normalized version of of this vector. That is, a vector in the same
1465
        direction as A, but with a length of 1.
1466

1467
      @bold(Note): this is an SIMD optimized version that uses an approximation,
1468
      resulting in a small error. For an accurate version, use Normalize.
1469

1470
      @bold(Note): Does not change this vector. To update this vector itself,
1471
      use SetNormalizedFast. }
1472
    function NormalizeFast: TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1473

1474
    { Normalizes this vector. This is, keep the current direction, but set the
1475
      length to 1.
1476

1477
      @bold(Note): this is an SIMD optimized version that uses an approximation,
1478
      resulting in a small error. For an accurate version, use SetNormalized.
1479

1480
      @bold(Note): If you do not want to change this vector, but get a
1481
      normalized version instead, then use NormalizeFast. }
1482
    procedure SetNormalizedFast; {$IFDEF FM_INLINE}inline;{$ENDIF}
1483

1484
    { Calculates a vector pointing in the same direction as this vector.
1485

1486
      Parameters:
1487
        I: the incident vector.
1488
        NRef: the reference vector.
1489

1490
      Returns:
1491
        A vector that points away from the surface as defined by its normal. If
1492
        NRef.Dot(I) < 0 then it returns this vector, otherwise it returns the
1493
        negative of this vector. }
1494
    function FaceForward(const I, NRef: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1495

1496
    { Calculates the reflection direction for this (incident) vector.
1497

1498
      Parameters:
1499
        N: the normal vector. Should be normalized in order to achieve the desired
1500
          result.
1501

1502
      Returns:
1503
        The reflection direction calculated as Self - 2 * N.Dot(Self) * N. }
1504
    function Reflect(const N: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1505

1506
    { Calculates the refraction direction for this (incident) vector.
1507

1508
      Parameters:
1509
        N: the normal vector. Should be normalized in order to achieve the
1510
          desired result.
1511
        Eta: the ratio of indices of refraction.
1512

1513
      Returns:
1514
        The refraction vector.
1515

1516
      @bold(Note): This vector should be normalized in order to achieve the
1517
      desired result.}
1518
    function Refract(const N: TVector4; const Eta: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1519

1520
    { Creates a vector with the same direction as this vector, but with the
1521
      length limited, based on the desired maximum length.
1522

1523
      Parameters:
1524
        AMaxLength: The desired maximum length of the vector.
1525

1526
      Returns:
1527
        A length-limited version of this vector.
1528

1529
      @bold(Note): Does not change this vector. To update this vector itself,
1530
      use SetLimit. }
1531
    function Limit(const AMaxLength: Single): TVector4; inline;
1532

1533
    { Limits the length of this vector, based on the desired maximum length.
1534

1535
      Parameters:
1536
        AMaxLength: The desired maximum length of this vector.
1537

1538
      @bold(Note): If you do not want to change this vector, but get a
1539
      length-limited version instead, then use Limit. }
1540
    procedure SetLimit(const AMaxLength: Single); inline;
1541

1542
    { Creates a vector with the same direction as this vector, but with the
1543
      length limited, based on the desired squared maximum length.
1544

1545
      Parameters:
1546
        AMaxLengthSquared: The desired squared maximum length of the vector.
1547

1548
      Returns:
1549
        A length-limited version of this vector.
1550

1551
      @bold(Note): Does not change this vector. To update this vector itself,
1552
      use SetLimitSquared. }
1553
    function LimitSquared(const AMaxLengthSquared: Single): TVector4;
1554

1555
    { Limits the length of this vector, based on the desired squared maximum
1556
      length.
1557

1558
      Parameters:
1559
        AMaxLengthSquared: The desired squared maximum length of this vector.
1560

1561
      @bold(Note): If you do not want to change this vector, but get a
1562
      length-limited version instead, then use LimitSquared. }
1563
    procedure SetLimitSquared(const AMaxLengthSquared: Single);
1564

1565
    { Creates a vector with the same direction as this vector, but with the
1566
      length clamped between a minimim and maximum length.
1567

1568
      Parameters:
1569
        AMinLength: The minimum length of the vector.
1570
        AMaxLength: The maximum length of the vector.
1571

1572
      Returns:
1573
        A length-clamped version of this vector.
1574

1575
      @bold(Note): Does not change this vector. To update this vector itself,
1576
      use SetClamped. }
1577
    function Clamp(const AMinLength, AMaxLength: Single): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
1578

1579
    { Clamps the length of this vector between a minimim and maximum length.
1580

1581
      Parameters:
1582
        AMinLength: The minimum length of this vector.
1583
        AMaxLength: The maximum length of this vector.
1584

1585
      @bold(Note): If you do not want to change this vector, but get a
1586
      length-clamped version instead, then use Clamp. }
1587
    procedure SetClamped(const AMinLength, AMaxLength: Single);
1588

1589
    { Linearly interpolates between this vector and a target vector.
1590

1591
      Parameters:
1592
        ATarget: the target vector.
1593
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
1594

1595
      Returns:
1596
        The interpolation result vector.
1597

1598
      @bold(Note): Does not change this vector. To update this vector itself,
1599
      use SetLerp. }
1600
    function Lerp(const ATarget: TVector4; const AAlpha: Single): TVector4; inline;
1601

1602
    { Linearly interpolates between this vector and a target vector and stores
1603
      the result in this vector.
1604

1605
      Parameters:
1606
        ATarget: the target vector.
1607
        AAlpha: the interpolation coefficient (between 0.0 and 1.0).
1608

1609
      @bold(Note): If you do not want to change this vector, but get an
1610
      interpolated version instead, then use Lerp. }
1611
    procedure SetLerp(const ATarget: TVector4; const AAlpha: Single); inline;
1612

1613
    { Whether the vector is normalized (within a small margin of error).
1614

1615
      Returns:
1616
        True if the length of the vector is (very close to) 1.0 }
1617
    function IsNormalized: Boolean; overload; inline;
1618

1619
    { Whether the vector is normalized within a given margin of error.
1620

1621
      Parameters:
1622
        AErrorMargin: the allowed margin of error.
1623

1624
      Returns:
1625
        True if the squared length of the vector is 1.0 within the margin of
1626
        error. }
1627
    function IsNormalized(const AErrorMargin: Single): Boolean; overload;
1628

1629
    { Whether this is a zero vector.
1630

1631
      Returns:
1632
        True if X, Y, Z and W are exactly 0.0 }
1633
    function IsZero: Boolean; overload; inline;
1634

1635
    { Whether this is a zero vector within a given margin of error.
1636

1637
      Parameters:
1638
        AErrorMargin: the allowed margin of error.
1639

1640
      Returns:
1641
        True if the squared length is smaller then the margin of error. }
1642
    function IsZero(const AErrorMargin: Single): Boolean; overload;
1643

1644
    { Whether this vector has a similar direction compared to another vector.
1645
      The test is performed in 3 dimensions (that is, the W-component is ignored).
1646
      Parameters:
1647
        AOther: the other vector.
1648

1649
      Returns:
1650
        True if the normalized dot product (ignoring the W-component) is greater
1651
        than 0. }
1652
    function HasSameDirection(const AOther: TVector4): Boolean; inline;
1653

1654
    { Whether this vector has an opposite direction compared to another vector.
1655
      The test is performed in 3 dimensions (that is, the W-component is ignored).
1656

1657
      Parameters:
1658
        AOther: the other vector.
1659

1660
      Returns:
1661
        True if the normalized dot product (ignoring the W-component) is less
1662
        than 0. }
1663
    function HasOppositeDirection(const AOther: TVector4): Boolean; inline;
1664

1665
    { Whether this vector runs parallel to another vector (either in the same
1666
      or the opposite direction). The test is performed in 3 dimensions (that
1667
      is, the W-component is ignored).
1668

1669
      Parameters:
1670
        AOther: the other vector.
1671
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1672
          is used.
1673

1674
      Returns:
1675
        True if this vector runs parallel to AOther (within the given tolerance
1676
        and ignoring the W-component) }
1677
    function IsParallel(const AOther: TVector4; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1678

1679
    { Whether this vector is collinear with another vector. Two vectors are
1680
      collinear if they run parallel to each other and point in the same
1681
      direction. The test is performed in 3 dimensions (that is, the W-component
1682
      is ignored).
1683

1684
      Parameters:
1685
        AOther: the other vector.
1686
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1687
          is used.
1688

1689
      Returns:
1690
        True if this vector is collinear to AOther (within the given tolerance
1691
        and ignoring the W-component) }
1692
    function IsCollinear(const AOther: TVector4; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1693

1694
    { Whether this vector is opposite collinear with another vector. Two vectors
1695
      are opposite collinear if they run parallel to each other and point in
1696
      opposite directions. The test is performed in 3 dimensions (that is, the
1697
      W-component is ignored).
1698

1699
      Parameters:
1700
        AOther: the other vector.
1701
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1702
          is used.
1703

1704
      Returns:
1705
        True if this vector is opposite collinear to AOther (within the given
1706
        tolerance and ignoring the W-component) }
1707
    function IsCollinearOpposite(const AOther: TVector4; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1708

1709
    { Whether this vector is perpendicular to another vector. The test is
1710
    performed in 3 dimensions (that is, the W-component is ignored).
1711

1712
      Parameters:
1713
        AOther: the other vector.
1714
        ATolerance: (optional) tolerance. If not specified, a small tolerance
1715
          is used.
1716

1717
      Returns:
1718
        True if this vector is perpendicular to AOther. That is, if the dot
1719
        product is 0 (within the given tolerance and ignoring the W-component) }
1720
    function IsPerpendicular(const AOther: TVector4; const ATolerance: Single = SINGLE_TOLERANCE): Boolean;
1721

1722
    { Returns the components of the vector.
1723
      This is identical to accessing the C-field, but this property can be used
1724
      as a default array property.
1725

1726
      Parameters:
1727
        AIndex: index of the component to return (0-3). Range is checked
1728
          with an assertion. }
1729
    property Components[const AIndex: Integer]: Single read GetComponent write SetComponent; default;
1730

1731
    { The euclidean length of this vector.
1732

1733
      @bold(Note): If you only want to compare lengths of vectors, you should
1734
      use LengthSquared instead, which is faster.
1735

1736
      @bold(Note): You can also set the length of the vector. In that case, it
1737
      will keep the current direction. }
1738
    property Length: Single read GetLength write SetLength;
1739

1740
    { The squared length of the vector.
1741

1742
      @bold(Note): This property is faster than Length because it avoids
1743
      calculating a square root. It is useful for comparing lengths instead of
1744
      calculating actual lengths.
1745

1746
      @bold(Note): You can also set the squared length of the vector. In that
1747
      case, it will keep the current direction. }
1748
    property LengthSquared: Single read GetLengthSquared write SetLengthSquared;
1749
  public
1750
    case Byte of
1751
      { X, Y, Z and W components of the vector. Aliases for C[0], C[1], C[2]
1752
        and C[3]. }
1753
      0: (X, Y, Z, W: Single);
1754

1755
      { Red, Green, Blue and Alpha components of the vector. Aliases for C[0],
1756
        C[1], C[2] and C[3]. }
1757
      1: (R, G, B, A: Single);
1758

1759
      { S, T, P and Q components of the vector. Aliases for C[0], C[1], C[2] and
1760
        C[3]. }
1761
      2: (S, T, P, Q: Single);
1762

1763
      { The four components of the vector. }
1764
      3: (C: array [0..3] of Single);
1765
  end;
1766
  PVector4 = ^TVector4;
1767

1768
type
1769
  { A 2x2 matrix in row-major order (M[Row, Column]).
1770
    You can access the elements directly using M[0,0]..M[1,1] or m11..m22.
1771
    You can also access the matrix using its two rows R[0]..R[1] (which map
1772
    directly to the elements M[]).
1773

1774
    When the conditional define FM_COLUMN_MAJOR is set, the matrix is stored
1775
    in column-major order instead (M[Column, Row]), and the Rows property
1776
    and R fields are replaced by Columns and C respectively. }
1777
  TMatrix2 = record
1778
  {$REGION 'Internal Declarations'}
1779
  private
1780
    {$IFDEF FM_COLUMN_MAJOR}
1781
    function GetComponent(const AColumn, ARow: Integer): Single; inline;
1782
    procedure SetComponent(const AColumn, ARow: Integer; const Value: Single); inline;
1783
    function GetColumn(const AIndex: Integer): TVector2; inline;
1784
    procedure SetColumn(const AIndex: Integer; const Value: TVector2); inline;
1785
    {$ELSE}
1786
    function GetComponent(const ARow, AColumn: Integer): Single; inline;
1787
    procedure SetComponent(const ARow, AColumn: Integer; const Value: Single); inline;
1788
    function GetRow(const AIndex: Integer): TVector2; inline;
1789
    procedure SetRow(const AIndex: Integer; const Value: TVector2); inline;
1790
    {$ENDIF}
1791
    function GetDeterminant: Single; inline;
1792
  {$ENDREGION 'Internal Declarations'}
1793
  public
1794
    { Initializes the matrix to an identity matrix (filled with 0 and value 1
1795
      for the diagonal) }
1796
    procedure Init; overload; inline;
1797

1798
    { Fills the matrix with zeros and sets the diagonal.
1799

1800
      Parameters:
1801
        ADiagonal: the value to use for the diagonal. Use 1 to set the matrix
1802
          to an identity matrix. }
1803
    procedure Init(const ADiagonal: Single); overload; inline;
1804

1805
    {$IFDEF FM_COLUMN_MAJOR}
1806
    { Initializes the matrix using two column vectors.
1807

1808
      Parameters:
1809
        AColumn0: the first column of the matrix.
1810
        AColumn1: the second column of the matrix. }
1811
    procedure Init(const AColumn0, AColumn1: TVector2); overload; inline;
1812
    {$ELSE}
1813
    { Initializes the matrix using two row vectors.
1814

1815
      Parameters:
1816
        ARow0: the first row of the matrix.
1817
        ARow1: the second row of the matrix. }
1818
    procedure Init(const ARow0, ARow1: TVector2); overload; inline;
1819
    {$ENDIF}
1820

1821
    { Initializes the matrix with explicit values.
1822

1823
      Parameters:
1824
        A11-A12: the values of the matrix elements, in row-major order. }
1825
    procedure Init(const A11, A12, A21, A22: Single); overload; inline;
1826

1827
    { Checks two matrices for equality.
1828

1829
      Returns:
1830
        True if the two matrices match each other exactly. }
1831
    class operator Equal(const A, B: TMatrix2): Boolean; inline;
1832

1833
    { Checks two matrices for inequality.
1834

1835
      Returns:
1836
        True if the two matrices are not equal. }
1837
    class operator NotEqual(const A, B: TMatrix2): Boolean; inline;
1838

1839
    { Negates a matrix.
1840

1841
      Returns:
1842
        The negative value of the matrix (with all elements negated). }
1843
    class operator Negative(const A: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1844

1845
    { Adds a scalar value to each element of a matrix. }
1846
    class operator Add(const A: TMatrix2; const B: Single): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1847

1848
    { Adds a scalar value to each element of a matrix. }
1849
    class operator Add(const A: Single; const B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1850

1851
    { Adds two matrices component-wise. }
1852
    class operator Add(const A, B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1853

1854
    { Subtracts a scalar value from each element of a matrix. }
1855
    class operator Subtract(const A: TMatrix2; const B: Single): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1856

1857
    { Subtracts a matrix from a scalar value. }
1858
    class operator Subtract(const A: Single; const B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1859

1860
    { Subtracts two matrices component-wise. }
1861
    class operator Subtract(const A, B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1862

1863
    { Multiplies a matrix with a scalar value. }
1864
    class operator Multiply(const A: TMatrix2; const B: Single): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1865

1866
    { Multiplies a matrix with a scalar value. }
1867
    class operator Multiply(const A: Single; const B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1868

1869
    { Performs a matrix * row vector linear algebraic multiplication. }
1870
    class operator Multiply(const A: TMatrix2; const B: TVector2): TVector2; inline;
1871

1872
    { Performs a column vector * matrix linear algebraic multiplication. }
1873
    class operator Multiply(const A: TVector2; const B: TMatrix2): TVector2; inline;
1874

1875
    { Multiplies two matrices using linear algebraic multiplication. }
1876
    class operator Multiply(const A, B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1877

1878
    { Divides a matrix by a scalar value. }
1879
    class operator Divide(const A: TMatrix2; const B: Single): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1880

1881
    { Divides a scalar value by a matrix. }
1882
    class operator Divide(const A: Single; const B: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1883

1884
    { Divides a matrix by a vector. This is equivalent to multiplying the
1885
      inverse of the matrix with a row vector using linear algebraic
1886
      multiplication. }
1887
    class operator Divide(const A: TMatrix2; const B: TVector2): TVector2; inline;
1888

1889
    { Divides a vector by a matrix. This is equivalent to multiplying a column
1890
      vector with the inverse of the matrix using linear algebraic
1891
      multiplication. }
1892
    class operator Divide(const A: TVector2; const B: TMatrix2): TVector2; inline;
1893

1894
    { Divides two matrices. This is equivalent to multiplying the first matrix
1895
      with the inverse of the second matrix using linear algebraic
1896
      multiplication. }
1897
    class operator Divide(const A, B: TMatrix2): TMatrix2; inline;
1898

1899
    { Multiplies this matrix with another matrix component-wise.
1900

1901
      Parameters:
1902
        AOther: the other matrix.
1903

1904
      Returns:
1905
        This matrix multiplied by AOther component-wise.
1906
        That is, Result.M[I,J] := M[I,J] * AOther.M[I,J].
1907

1908
      @bold(Note): For linear algebraic matrix multiplication, use the multiply
1909
      (*) operator instead. }
1910
    function CompMult(const AOther: TMatrix2): TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1911

1912
    { Creates a transposed version of this matrix.
1913

1914
      Returns:
1915
        The transposed version of this matrix.
1916

1917
      @bold(Note): Does not change this matrix. To update this itself, use
1918
      SetTransposed. }
1919
    function Transpose: TMatrix2; inline;
1920

1921
    { Transposes this matrix.
1922

1923
      @bold(Note): If you do not want to change this matrix, but get a
1924
      transposed version instead, then use Transpose. }
1925
    procedure SetTransposed; inline;
1926

1927
    { Calculates the inverse of this matrix.
1928

1929
      Returns:
1930
        The inverse of this matrix.
1931

1932
      @bold(Note): Does not change this matrix. To update this itself, use
1933
      SetInversed.
1934

1935
      @bold(Note): The values in the returned matrix are undefined if this
1936
      matrix is singular or poorly conditioned (nearly singular). }
1937
    function Inverse: TMatrix2; {$IFDEF FM_INLINE}inline;{$ENDIF}
1938

1939
    { Inverts this matrix.
1940

1941
      @bold(Note): If you do not want to change this matrix, but get an
1942
      inversed version instead, then use Inverse.
1943

1944
      @bold(Note): The values in the inversed matrix are undefined if this
1945
      matrix is singular or poorly conditioned (nearly singular). }
1946
    procedure SetInversed;
1947

1948
    {$IFDEF FM_COLUMN_MAJOR}
1949
    { Returns the columns of the matrix. This is identical to accessing the
1950
      C-field.
1951

1952
      Parameters:
1953
        AIndex: index of the row to return (0 or 1). Range is checked with
1954
          an assertion. }
1955
    property Columns[const AIndex: Integer]: TVector2 read GetColumn write SetColumn;
1956

1957
    { Returns the elements of the matrix (in column-major order).
1958
      This is identical to accessing the M-field, but this property can be used
1959
      as a default array property.
1960

1961
      Parameters:
1962
        AColumn: the column index (0 or 1). Range is checked with an assertion.
1963
        ARow: the row index (0 or 1). Range is checked with an assertion. }
1964
    property Components[const AColumn, ARow: Integer]: Single read GetComponent write SetComponent; default;
1965
    {$ELSE}
1966
    { Returns the rows of the matrix. This is identical to accessing the
1967
      R-field.
1968

1969
      Parameters:
1970
        AIndex: index of the column to return (0 or 1). Range is checked with
1971
          an assertion. }
1972
    property Rows[const AIndex: Integer]: TVector2 read GetRow write SetRow;
1973

1974
    { Returns the elements of the matrix (in row-major order).
1975
      This is identical to accessing the M-field, but this property can be used
1976
      as a default array property.
1977

1978
      Parameters:
1979
        ARow: the row index (0 or 1). Range is checked with an assertion.
1980
        AColumn: the column index (0 or 1). Range is checked with an assertion. }
1981
    property Components[const ARow, AColumn: Integer]: Single read GetComponent write SetComponent; default;
1982
    {$ENDIF}
1983

1984
    { The determinant of this matrix. }
1985
    property Determinant: Single read GetDeterminant;
1986
  public
1987
    case Byte of
1988
      { Row or column vectors, depending on FM_COLUMN_MAJOR define }
1989
      0: (V: array [0..1] of TVector2);
1990

1991
      {$IFDEF FM_COLUMN_MAJOR}
1992
      { The two column vectors making up the matrix }
1993
      1: (C: array [0..1] of TVector2);
1994
      {$ELSE}
1995
      { The two row vectors making up the matrix }
1996
      2: (R: array [0..1] of TVector2);
1997
      {$ENDIF}
1998

1999
      { The elements of the matrix in row-major order }
2000
      3: (M: array [0..1, 0..1] of Single);
2001
      4: (m11, m12: Single;
2002
          m21, m22: Single);
2003
  end;
2004
  PMatrix2 = ^TMatrix2;
2005

2006
type
2007
  { A 3x3 matrix in row-major order (M[Row, Column]).
2008
    You can access the elements directly using M[0,0]..M[2,2] or m11..m33.
2009
    You can also access the matrix using its three rows R[0]..R[2] (which map
2010
    directly to the elements M[]).
2011

2012
    TMatrix3 is compatible with TMatrix in the Delphi RTL. You can typecast
2013
    between these two types or implicitly convert from one to the other through
2014
    assignment (eg. MyMatrix3 := MyMatrix).
2015

2016
    When the conditional define FM_COLUMN_MAJOR is set, the matrix is stored
2017
    in column-major order instead (M[Column, Row]), and the Rows property
2018
    and R fields are replaced by Columns and C respectively. Also, in that case
2019
    assigning an RTL TMatrix to a TMatrix3 will transpose the matrix to keep
2020
    behavior the same. }
2021
  TMatrix3 = record
2022
  {$REGION 'Internal Declarations'}
2023
  private
2024
    {$IFDEF FM_COLUMN_MAJOR}
2025
    function GetComponent(const AColumn, ARow: Integer): Single; inline;
2026
    procedure SetComponent(const AColumn, ARow: Integer; const Value: Single); inline;
2027
    function GetColumn(const AIndex: Integer): TVector3; inline;
2028
    procedure SetColumn(const AIndex: Integer; const Value: TVector3); inline;
2029
    {$ELSE}
2030
    function GetComponent(const ARow, AColumn: Integer): Single; inline;
2031
    procedure SetComponent(const ARow, AColumn: Integer; const Value: Single); inline;
2032
    function GetRow(const AIndex: Integer): TVector3; inline;
2033
    procedure SetRow(const AIndex: Integer; const Value: TVector3); inline;
2034
    {$ENDIF}
2035
    function GetDeterminant: Single;
2036
  {$ENDREGION 'Internal Declarations'}
2037
  public
2038
    { Initializes the matrix to an identity matrix (filled with 0 and value 1
2039
      for the diagonal) }
2040
    procedure Init; overload; inline;
2041

2042
    { Fills the matrix with zeros and sets the diagonal.
2043

2044
      Parameters:
2045
        ADiagonal: the value to use for the diagonal. Use 1 to set the matrix
2046
          to an identity matrix. }
2047
    procedure Init(const ADiagonal: Single); overload; inline;
2048

2049
    {$IFDEF FM_COLUMN_MAJOR}
2050
    { Initializes the matrix using three column vectors.
2051

2052
      Parameters:
2053
        AColumn0: the first column of the matrix.
2054
        AColumn1: the second column of the matrix.
2055
        AColumn2: the third column of the matrix. }
2056
    procedure Init(const AColumn0, AColumn1, AColumn2: TVector3); overload; inline;
2057
    {$ELSE}
2058
    { Initializes the matrix using three row vectors.
2059

2060
      Parameters:
2061
        ARow0: the first row of the matrix.
2062
        ARow1: the second row of the matrix.
2063
        ARow2: the third row of the matrix. }
2064
    procedure Init(const ARow0, ARow1, ARow2: TVector3); overload; inline;
2065
    {$ENDIF}
2066

2067
    { Initializes the matrix with explicit values.
2068

2069
      Parameters:
2070
        A11-A33: the values of the matrix elements, in row-major order. }
2071
    procedure Init(const A11, A12, A13, A21, A22, A23, A31, A32, A33: Single); overload; inline;
2072

2073
    { Initializes the matrix with a 2x2 matrix. The 2x2 matrix is copied to the
2074
      top-left corner of the 3x3 matrix, and the remaining elements are set
2075
      according to an identity matrix.
2076

2077
      Parameters:
2078
        AMatrix: the source 2x2 matrix. }
2079
    procedure Init(const AMatrix: TMatrix2); overload; inline;
2080

2081
    { Creates a scaling matrix that scales uniformly.
2082

2083
      Parameters:
2084
        AScale: the uniform scale factor }
2085
    procedure InitScaling(const AScale: Single); overload;
2086

2087
    { Creates a scaling matrix.
2088

2089
      Parameters:
2090
        AScaleX: the value to scale by on the X axis
2091
        AScaleY: the value to scale by on the Y axis }
2092
    procedure InitScaling(const AScaleX, AScaleY: Single); overload; inline;
2093

2094
    { Creates a scaling matrix.
2095

2096
      Parameters:
2097
        AScale: the scale factors }
2098
    procedure InitScaling(const AScale: TVector2); overload; inline;
2099

2100
    { Creates a translation matrix.
2101

2102
      Parameters:
2103
        ADeltaX: translation in the X direction
2104
        ADeltaY: translation in the Y direction }
2105
    procedure InitTranslation(const ADeltaX, ADeltaY: Single); overload; inline;
2106

2107
    { Creates a translation matrix.
2108

2109
      Parameters:
2110
        ADelta: translation vector }
2111
    procedure InitTranslation(const ADelta: TVector2); overload; inline;
2112

2113
    { Creates a rotation the matrix using a rotation angle in radians.
2114

2115
      Parameters:
2116
        AAngle: the rotation angle in radians }
2117
    procedure InitRotation(const AAngle: Single);
2118

2119
    { Implicitly converts a TMatrix to a TMatrix3. }
2120
    class operator Implicit(const A: TMatrix): TMatrix3; inline;
2121

2122
    { Implicitly converts a TMatrix3 to a TMatrix. }
2123
    class operator Implicit(const A: TMatrix3): TMatrix; inline;
2124

2125
    { Checks two matrices for equality.
2126

2127
      Returns:
2128
        True if the two matrices match each other exactly. }
2129
    class operator Equal(const A, B: TMatrix3): Boolean; inline;
2130

2131
    { Checks two matrices for inequality.
2132

2133
      Returns:
2134
        True if the two matrices are not equal. }
2135
    class operator NotEqual(const A, B: TMatrix3): Boolean; inline;
2136

2137
    { Negates a matrix.
2138

2139
      Returns:
2140
        The negative value of the matrix (with all elements negated). }
2141
    class operator Negative(const A: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2142

2143
    { Adds a scalar value to each element of a matrix. }
2144
    class operator Add(const A: TMatrix3; const B: Single): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2145

2146
    { Adds a scalar value to each element of a matrix. }
2147
    class operator Add(const A: Single; const B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2148

2149
    { Adds two matrices component-wise. }
2150
    class operator Add(const A, B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2151

2152
    { Subtracts a scalar value from each element of a matrix. }
2153
    class operator Subtract(const A: TMatrix3; const B: Single): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2154

2155
    { Subtracts a matrix from a scalar value. }
2156
    class operator Subtract(const A: Single; const B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2157

2158
    { Subtracts two matrices component-wise. }
2159
    class operator Subtract(const A, B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2160

2161
    { Multiplies a matrix with a scalar value. }
2162
    class operator Multiply(const A: TMatrix3; const B: Single): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2163

2164
    { Multiplies a matrix with a scalar value. }
2165
    class operator Multiply(const A: Single; const B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2166

2167
    { Performs a matrix * row vector linear algebraic multiplication. }
2168
    class operator Multiply(const A: TMatrix3; const B: TVector3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2169

2170
    { Performs a column vector * matrix linear algebraic multiplication. }
2171
    class operator Multiply(const A: TVector3; const B: TMatrix3): TVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2172

2173
    { Multiplies two matrices using linear algebraic multiplication. }
2174
    class operator Multiply(const A, B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2175

2176
    { Divides a matrix by a scalar value. }
2177
    class operator Divide(const A: TMatrix3; const B: Single): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2178

2179
    { Divides a scalar value by a matrix. }
2180
    class operator Divide(const A: Single; const B: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2181

2182
    { Divides a matrix by a vector. This is equivalent to multiplying the
2183
      inverse of the matrix with a row vector using linear algebraic
2184
      multiplication. }
2185
    class operator Divide(const A: TMatrix3; const B: TVector3): TVector3; inline;
2186

2187
    { Divides a vector by a matrix. This is equivalent to multiplying a column
2188
      vector with the inverse of the matrix using linear algebraic
2189
      multiplication. }
2190
    class operator Divide(const A: TVector3; const B: TMatrix3): TVector3; inline;
2191

2192
    { Divides two matrices. This is equivalent to multiplying the first matrix
2193
      with the inverse of the second matrix using linear algebraic
2194
      multiplication. }
2195
    class operator Divide(const A, B: TMatrix3): TMatrix3; inline;
2196

2197
    { Multiplies this matrix with another matrix component-wise.
2198

2199
      Parameters:
2200
        AOther: the other matrix.
2201

2202
      Returns:
2203
        This matrix multiplied by AOther component-wise.
2204
        That is, Result.M[I,J] := M[I,J] * AOther.M[I,J].
2205

2206
      @bold(Note): For linear algebraic matrix multiplication, use the multiply
2207
      (*) operator instead. }
2208
    function CompMult(const AOther: TMatrix3): TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2209

2210
    { Creates a transposed version of this matrix.
2211

2212
      Returns:
2213
        The transposed version of this matrix.
2214

2215
      @bold(Note): Does not change this matrix. To update this itself, use
2216
      SetTransposed. }
2217
    function Transpose: TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2218

2219
    { Transposes this matrix.
2220

2221
      @bold(Note): If you do not want to change this matrix, but get a
2222
      transposed version instead, then use Transpose. }
2223
    procedure SetTransposed;
2224

2225
    { Calculates the inverse of this matrix.
2226

2227
      Returns:
2228
        The inverse of this matrix.
2229

2230
      @bold(Note): Does not change this matrix. To update this itself, use
2231
      SetInversed.
2232

2233
      @bold(Note): The values in the returned matrix are undefined if this
2234
      matrix is singular or poorly conditioned (nearly singular). }
2235
    function Inverse: TMatrix3; {$IFDEF FM_INLINE}inline;{$ENDIF}
2236

2237
    { Inverts this matrix.
2238

2239
      @bold(Note): If you do not want to change this matrix, but get an
2240
      inversed version instead, then use Inverse.
2241

2242
      @bold(Note): The values in the inversed matrix are undefined if this
2243
      matrix is singular or poorly conditioned (nearly singular). }
2244
    procedure SetInversed;
2245

2246
    {$IFDEF FM_COLUMN_MAJOR}
2247
    { Returns the columns of the matrix. This is identical to accessing the
2248
      C-field.
2249

2250
      Parameters:
2251
        AIndex: index of the column to return (0-2). Range is checked with
2252
          an assertion. }
2253
    property Columns[const AIndex: Integer]: TVector3 read GetColumn write SetColumn;
2254

2255
    { Returns the elements of the matrix (in column-major order).
2256
      This is identical to accessing the M-field, but this property can be used
2257
      as a default array property.
2258

2259
      Parameters:
2260
        AColumn: the column index (0-2). Range is checked with an assertion.
2261
        ARow: the row index (0-2). Range is checked with an assertion. }
2262
    property Components[const AColumn, ARow: Integer]: Single read GetComponent write SetComponent; default;
2263
    {$ELSE}
2264
    { Returns the rows of the matrix. This is identical to accessing the
2265
      R-field.
2266

2267
      Parameters:
2268
        AIndex: index of the row to return (0-2). Range is checked with
2269
          an assertion. }
2270
    property Rows[const AIndex: Integer]: TVector3 read GetRow write SetRow;
2271

2272
    { Returns the elements of the matrix (in row-major order).
2273
      This is identical to accessing the M-field, but this property can be used
2274
      as a default array property.
2275

2276
      Parameters:
2277
        ARow: the row index (0-2). Range is checked with an assertion.
2278
        AColumn: the column index (0-2). Range is checked with an assertion. }
2279
    property Components[const ARow, AColumn: Integer]: Single read GetComponent write SetComponent; default;
2280
    {$ENDIF}
2281

2282
    { The determinant of this matrix. }
2283
    property Determinant: Single read GetDeterminant;
2284
  public
2285
    case Byte of
2286
      { Row or column vectors, depending on FM_COLUMN_MAJOR define }
2287
      0: (V: array [0..2] of TVector3);
2288

2289
      {$IFDEF FM_COLUMN_MAJOR}
2290
      { The three column vectors making up the matrix }
2291
      1: (C: array [0..2] of TVector3);
2292
      {$ELSE}
2293
      { The three row vectors making up the matrix }
2294
      2: (R: array [0..2] of TVector3);
2295
      {$ENDIF}
2296

2297
      { The elements of the matrix in row-major order }
2298
      3: (M: array [0..2, 0..2] of Single);
2299
      4: (m11, m12, m13: Single;
2300
          m21, m22, m23: Single;
2301
          m31, m32, m33: Single);
2302
  end;
2303
  PMatrix3 = ^TMatrix3;
2304

2305
type
2306
  { A 4x4 matrix in row-major order (M[Row, Column]).
2307
    You can access the elements directly using M[0,0]..M[3,3] or m11..m44.
2308
    You can also access the matrix using its four rows R[0]..R[3] (which map
2309
    directly to the elements M[]).
2310

2311
    TMatrix4 is compatible with TMatrix3D in the Delphi RTL. You can typecast
2312
    between these two types or implicitly convert from one to the other through
2313
    assignment (eg. MyMatrix4 := MyMatrix3D).
2314

2315
    When the conditional define FM_COLUMN_MAJOR is set, the matrix is stored
2316
    in column-major order instead (M[Column, Row]), and the Rows property
2317
    and R fields are replaced by Columns and C respectively. Also, in that case
2318
    assigning an RTL TMatrix3D to a TMatrix4 will transpose the matrix to keep
2319
    behavior the same. }
2320
  TMatrix4 = record
2321
  {$REGION 'Internal Declarations'}
2322
  private
2323
    {$IFDEF FM_COLUMN_MAJOR}
2324
    function GetComponent(const AColumn, ARow: Integer): Single; inline;
2325
    procedure SetComponent(const AColumn, ARow: Integer; const Value: Single); inline;
2326
    function GetColumn(const AIndex: Integer): TVector4; inline;
2327
    procedure SetColumn(const AIndex: Integer; const Value: TVector4); inline;
2328
    {$ELSE}
2329
    function GetComponent(const ARow, AColumn: Integer): Single; inline;
2330
    procedure SetComponent(const ARow, AColumn: Integer; const Value: Single); inline;
2331
    function GetRow(const AIndex: Integer): TVector4; inline;
2332
    procedure SetRow(const AIndex: Integer; const Value: TVector4); inline;
2333
    {$ENDIF}
2334
    function GetDeterminant: Single;
2335
  {$ENDREGION 'Internal Declarations'}
2336
  public
2337
    { Initializes the matrix to an identity matrix (filled with 0 and value 1
2338
      for the diagonal) }
2339
    procedure Init; overload; inline;
2340

2341
    { Fills the matrix with zeros and sets the diagonal.
2342

2343
      Parameters:
2344
        ADiagonal: the value to use for the diagonal. Use 1 to set the matrix
2345
          to an identity matrix. }
2346
    procedure Init(const ADiagonal: Single); overload; inline;
2347

2348
    {$IFDEF FM_COLUMN_MAJOR}
2349
    { Initializes the matrix using four column vectors.
2350

2351
      Parameters:
2352
        AColumn0: the first column of the matrix.
2353
        AColumn1: the second column of the matrix.
2354
        AColumn2: the third column of the matrix.
2355
        AColumn3: the fourth column of the matrix. }
2356
    procedure Init(const AColumn0, AColumn1, AColumn2, AColumn3: TVector4); overload; inline;
2357
    {$ELSE}
2358
    { Initializes the matrix using four row vectors.
2359

2360
      Parameters:
2361
        ARow0: the first row of the matrix.
2362
        ARow1: the second row of the matrix.
2363
        ARow2: the third row of the matrix.
2364
        ARow3: the fourth row of the matrix. }
2365
    procedure Init(const ARow0, ARow1, ARow2, ARow3: TVector4); overload; inline;
2366
    {$ENDIF}
2367

2368
    { Initializes the matrix with explicit values.
2369

2370
      Parameters:
2371
        A11-A44: the values of the matrix elements, in row-major order. }
2372
    procedure Init(const A11, A12, A13, A14, A21, A22, A23, A24, A31, A32, A33,
2373
      A34, A41, A42, A43, A44: Single); overload; inline;
2374

2375
    { Initializes the matrix with a 2x2 matrix. The 2x2 matrix is copied to the
2376
      top-left corner of the 4x4 matrix, and the remaining elements are set
2377
      according to an identity matrix.
2378

2379
      Parameters:
2380
        AMatrix: the source 2x2 matrix. }
2381
    procedure Init(const AMatrix: TMatrix2); overload; inline;
2382

2383
    { Initializes the matrix with a 3x3 matrix. The 3x3 matrix is copied to the
2384
      top-left corner of the 4x4 matrix, and the remaining elements are set
2385
      according to an identity matrix.
2386

2387
      Parameters:
2388
        AMatrix: the source 3x3 matrix. }
2389
    procedure Init(const AMatrix: TMatrix3); overload; inline;
2390

2391
    { Creates a scaling matrix that scales uniformly.
2392

2393
      Parameters:
2394
        AScale: the uniform scale factor }
2395
    procedure InitScaling(const AScale: Single); overload;
2396

2397
    { Creates a scaling matrix.
2398

2399
      Parameters:
2400
        AScaleX: the value to scale by on the X axis
2401
        AScaleY: the value to scale by on the Y axis
2402
        AScaleZ: the value to scale by on the Z axis }
2403
    procedure InitScaling(const AScaleX, AScaleY, AScaleZ: Single); overload; inline;
2404

2405
    { Creates a scaling matrix.
2406

2407
      Parameters:
2408
        AScale: the scale factors }
2409
    procedure InitScaling(const AScale: TVector3); overload; inline;
2410

2411
    { Creates a translation matrix.
2412

2413
      Parameters:
2414
        ADeltaX: translation in the X direction
2415
        ADeltaY: translation in the Y direction
2416
        ADeltaZ: translation in the Z direction }
2417
    procedure InitTranslation(const ADeltaX, ADeltaY, ADeltaZ: Single); overload; inline;
2418

2419
    { Creates a translation matrix.
2420

2421
      Parameters:
2422
        ADelta: translation vector }
2423
    procedure InitTranslation(const ADelta: TVector3); overload; inline;
2424

2425
    { Creates a matrix for rotating points around the X axis.
2426

2427
      Parameters:
2428
        AAngle: the rotation angle around the X axis, in radians }
2429
    procedure InitRotationX(const AAngle: Single);
2430

2431
    { Creates a matrix for rotating points around the Y axis.
2432

2433
      Parameters:
2434
        AAngle: the rotation angle around the Y axis, in radians }
2435
    procedure InitRotationY(const AAngle: Single);
2436

2437
    { Creates a matrix for rotating points around the Z axis.
2438

2439
      Parameters:
2440
        AAngle: the rotation angle around the Z axis, in radians }
2441
    procedure InitRotationZ(const AAngle: Single);
2442

2443
    { Creates a matrix for rotating points around a certain axis.
2444

2445
      Parameters:
2446
        AAxis: the direction of the axis to rotate around.
2447
        AAngle: the rotation angle around AAxis, in radians }
2448
    procedure InitRotation(const AAxis: TVector3; const AAngle: Single);
2449

2450
    { Creates a rotation matrix from a yaw, pitch and roll angle.
2451

2452
      Parameters:
2453
        AYaw: the rotation angle around the Y axis, in radians
2454
        APitch: the rotation angle around the X axis, in radians
2455
        ARoll: the rotation angle around the Z axis, in radians }
2456
    procedure InitRotationYawPitchRoll(const AYaw, APitch, ARoll: Single);
2457

2458
    { Creates a rotation matrix from a heading, pitch and bank angle.
2459

2460
      Parameters:
2461
        AHeading: the heading angle, in radians
2462
        APitch: the pitch angle, in radians
2463
        ABank: the bank angle, in radians }
2464
    procedure InitRotationHeadingPitchBank(const AHeading, APitch, ABank: Single);
2465

2466
    { Creates a left-handed view matrix looking at a certain target.
2467

2468
      Parameters:
2469
        ACameraPosition: position of the camera (or eye).
2470
        ACameraTarget: the target towards which the camera is pointing.
2471
        ACameraUp: the direction that is "up" from the camera's point of view }
2472
    procedure InitLookAtLH(const ACameraPosition, ACameraTarget, ACameraUp: TVector3);
2473

2474
    { Creates a right-handed view matrix looking at a certain target.
2475

2476
      Parameters:
2477
        ACameraPosition: position of the camera (or eye).
2478
        ACameraTarget: the target towards which the camera is pointing.
2479
        ACameraUp: the direction that is "up" from the camera's point of view }
2480
    procedure InitLookAtRH(const ACameraPosition, ACameraTarget, ACameraUp: TVector3);
2481

2482
    { Creates a left-handed view matrix looking into a certain direction.
2483

2484
      Parameters:
2485
        ACameraPosition: position of the camera (or eye).
2486
        ACameraDirection: the direction the camera is pointing in.
2487
        ACameraUp: the direction that is "up" from the camera's point of view }
2488
    procedure InitLookAtDirLH(const ACameraPosition, ACameraDirection, ACameraUp: TVector3);
2489

2490
    { Creates a right-handed view matrix looking into a certain direction.
2491

2492
      Parameters:
2493
        ACameraPosition: position of the camera (or eye).
2494
        ACameraDirection: the direction the camera is pointing in.
2495
        ACameraUp: the direction that is "up" from the camera's point of view }
2496
    procedure InitLookAtDirRH(const ACameraPosition, ACameraDirection, ACameraUp: TVector3);
2497

2498
    { Creates a left-handed orthographic projection matrix from the given view
2499
      volume dimensions.
2500

2501
      Parameters:
2502
        AWidth: the width of the view volume.
2503
        AHeight: the height of the view volume.
2504
        AZNearPlane: the minimum Z-value of the view volume.
2505
        AZFarPlane: the maximum Z-value of the view volume. }
2506
    procedure InitOrthoLH(const AWidth, AHeight, AZNearPlane, AZFarPlane: Single);
2507

2508
    { Creates a right-handed orthographic projection matrix from the given view
2509
      volume dimensions.
2510

2511
      Parameters:
2512
        AWidth: the width of the view volume.
2513
        AHeight: the height of the view volume.
2514
        AZNearPlane: the minimum Z-value of the view volume.
2515
        AZFarPlane: the maximum Z-value of the view volume. }
2516
    procedure InitOrthoRH(const AWidth, AHeight, AZNearPlane, AZFarPlane: Single);
2517

2518
    { Creates a customized left-handed orthographic projection matrix.
2519

2520
      Parameters:
2521
        ALeft: the minimum X-value of the view volume.
2522
        ATop: the maximum Y-value of the view volume.
2523
        ARight: the maximum X-value of the view volume.
2524
        ABottom: the minimum Y-value of the view volume.
2525
        AZNearPlane: the minimum Z-value of the view volume.
2526
        AZFarPlane: the maximum Z-value of the view volume. }
2527
    procedure InitOrthoOffCenterLH(const ALeft, ATop, ARight, ABottom,
2528
      AZNearPlane, AZFarPlane: Single);
2529

2530
    { Creates a customized right-handed orthographic projection matrix.
2531

2532
      Parameters:
2533
        ALeft: the minimum X-value of the view volume.
2534
        ATop: the maximum Y-value of the view volume.
2535
        ARight: the maximum X-value of the view volume.
2536
        ABottom: the minimum Y-value of the view volume.
2537
        AZNearPlane: the minimum Z-value of the view volume.
2538
        AZFarPlane: the maximum Z-value of the view volume. }
2539
    procedure InitOrthoOffCenterRH(const ALeft, ATop, ARight, ABottom,
2540
      AZNearPlane, AZFarPlane: Single);
2541

2542
    { Creates a left-handed perspective projection matrix based on a field of
2543
      view, aspect ratio, and near and far view plane distances.
2544

2545
      Parameters:
2546
        AFieldOfView: the field of view in radians.
2547
        AAspectRatio: the aspect ratio, defined as view space width divided by
2548
          height.
2549
        ANearPlaneDistance:the distance to the near view plane.
2550
        AFarPlaneDistance:the distance to the far view plane.
2551
        AHorizontalFOV: (optional) boolean indicating the direction of the
2552
          field of view. If False (default), AFieldOfView is in the Y direction,
2553
          otherwise in the X direction }
2554
    procedure InitPerspectiveFovLH(const AFieldOfView, AAspectRatio,
2555
      ANearPlaneDistance, AFarPlaneDistance: Single;
2556
      const AHorizontalFOV: Boolean = False);
2557

2558
    { Creates a right-handed perspective projection matrix based on a field of
2559
      view, aspect ratio, and near and far view plane distances.
2560

2561
      Parameters:
2562
        AFieldOfView: the field of view in radians.
2563
        AAspectRatio: the aspect ratio, defined as view space width divided by
2564
          height.
2565
        ANearPlaneDistance:the distance to the near view plane.
2566
        AFarPlaneDistance:the distance to the far view plane.
2567
        AHorizontalFOV: (optional) boolean indicating the direction of the
2568
          field of view. If False (default), AFieldOfView is in the Y direction,
2569
          otherwise in the X direction }
2570
    procedure InitPerspectiveFovRH(const AFieldOfView, AAspectRatio,
2571
      ANearPlaneDistance, AFarPlaneDistance: Single;
2572
      const AHorizontalFOV: Boolean = False);
2573

2574
    { Implicitly converts a TMatrix3D to a TMatrix4. }
2575
    class operator Implicit(const A: TMatrix3D): TMatrix4; inline;
2576

2577
    { Implicitly converts a TMatrix4 to a TMatrix3D. }
2578
    class operator Implicit(const A: TMatrix4): TMatrix3D; inline;
2579

2580
    { Checks two matrices for equality.
2581

2582
      Returns:
2583
        True if the two matrices match each other exactly. }
2584
    class operator Equal(const A, B: TMatrix4): Boolean; inline;
2585

2586
    { Checks two matrices for inequality.
2587

2588
      Returns:
2589
        True if the two matrices are not equal. }
2590
    class operator NotEqual(const A, B: TMatrix4): Boolean; inline;
2591

2592
    { Negates a matrix.
2593

2594
      Returns:
2595
        The negative value of the matrix (with all elements negated). }
2596
    class operator Negative(const A: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2597

2598
    { Adds a scalar value to each element of a matrix. }
2599
    class operator Add(const A: TMatrix4; const B: Single): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2600

2601
    { Adds a scalar value to each element of a matrix. }
2602
    class operator Add(const A: Single; const B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2603

2604
    { Adds two matrices component-wise. }
2605
    class operator Add(const A, B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2606

2607
    { Subtracts a scalar value from each element of a matrix. }
2608
    class operator Subtract(const A: TMatrix4; const B: Single): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2609

2610
    { Subtracts a matrix from a scalar value. }
2611
    class operator Subtract(const A: Single; const B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2612

2613
    { Subtracts two matrices component-wise. }
2614
    class operator Subtract(const A, B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2615

2616
    { Multiplies a matrix with a scalar value. }
2617
    class operator Multiply(const A: TMatrix4; const B: Single): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2618

2619
    { Multiplies a matrix with a scalar value. }
2620
    class operator Multiply(const A: Single; const B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2621

2622
    { Performs a matrix * row vector linear algebraic multiplication. }
2623
    class operator Multiply(const A: TMatrix4; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2624

2625
    { Performs a column vector * matrix linear algebraic multiplication. }
2626
    class operator Multiply(const A: TVector4; const B: TMatrix4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2627

2628
    { Multiplies two matrices using linear algebraic multiplication. }
2629
    class operator Multiply(const A, B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2630

2631
    { Divides a matrix by a scalar value. }
2632
    class operator Divide(const A: TMatrix4; const B: Single): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2633

2634
    { Divides a scalar value by a matrix. }
2635
    class operator Divide(const A: Single; const B: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2636

2637
    { Divides a matrix by a vector. This is equivalent to multiplying the
2638
      inverse of the matrix with a row vector using linear algebraic
2639
      multiplication. }
2640
    class operator Divide(const A: TMatrix4; const B: TVector4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2641

2642
    { Divides a vector by a matrix. This is equivalent to multiplying a column
2643
      vector with the inverse of the matrix using linear algebraic
2644
      multiplication. }
2645
    class operator Divide(const A: TVector4; const B: TMatrix4): TVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2646

2647
    { Divides two matrices. This is equivalent to multiplying the first matrix
2648
      with the inverse of the second matrix using linear algebraic
2649
      multiplication. }
2650
    class operator Divide(const A, B: TMatrix4): TMatrix4; inline;
2651

2652
    { Multiplies this matrix with another matrix component-wise.
2653

2654
      Parameters:
2655
        AOther: the other matrix.
2656

2657
      Returns:
2658
        This matrix multiplied by AOther component-wise.
2659
        That is, Result.M[I,J] := M[I,J] * AOther.M[I,J].
2660

2661
      @bold(Note): For linear algebraic matrix multiplication, use the multiply
2662
      (*) operator instead. }
2663
    function CompMult(const AOther: TMatrix4): TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2664

2665
    { Creates a transposed version of this matrix.
2666

2667
      Returns:
2668
        The transposed version of this matrix.
2669

2670
      @bold(Note): Does not change this matrix. To update this itself, use
2671
      SetTransposed. }
2672
    function Transpose: TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2673

2674
    { Transposes this matrix.
2675

2676
      @bold(Note): If you do not want to change this matrix, but get a
2677
      transposed version instead, then use Transpose. }
2678
    procedure SetTransposed;
2679

2680
    { Calculates the inverse of this matrix.
2681

2682
      Returns:
2683
        The inverse of this matrix.
2684

2685
      @bold(Note): Does not change this matrix. To update this itself, use
2686
      SetInversed.
2687

2688
      @bold(Note): The values in the returned matrix are undefined if this
2689
      matrix is singular or poorly conditioned (nearly singular). }
2690
    function Inverse: TMatrix4; {$IFDEF FM_INLINE}inline;{$ENDIF}
2691

2692
    { Inverts this matrix.
2693

2694
      @bold(Note): If you do not want to change this matrix, but get an
2695
      inversed version instead, then use Inverse.
2696

2697
      @bold(Note): The values in the inversed matrix are undefined if this
2698
      matrix is singular or poorly conditioned (nearly singular). }
2699
    procedure SetInversed;
2700

2701
    {$IFDEF FM_COLUMN_MAJOR}
2702
    { Returns the columns of the matrix. This is identical to accessing the
2703
      C-field.
2704

2705
      Parameters:
2706
        AIndex: index of the column to return (0-3). Range is checked with
2707
          an assertion. }
2708
    property Columns[const AIndex: Integer]: TVector4 read GetColumn write SetColumn;
2709

2710
    { Returns the elements of the matrix (in column-major order).
2711
      This is identical to accessing the M-field, but this property can be used
2712
      as a default array property.
2713

2714
      Parameters:
2715
        AColumn: the column index (0-3). Range is checked with an assertion.
2716
        ARow: the row index (0-3). Range is checked with an assertion. }
2717
    property Components[const AColumn, ARow: Integer]: Single read GetComponent write SetComponent; default;
2718
    {$ELSE}
2719
    { Returns the rows of the matrix. This is identical to accessing the
2720
      R-field.
2721

2722
      Parameters:
2723
        AIndex: index of the row to return (0-3). Range is checked with
2724
          an assertion. }
2725
    property Rows[const AIndex: Integer]: TVector4 read GetRow write SetRow;
2726

2727
    { Returns the elements of the matrix (in row-major order).
2728
      This is identical to accessing the M-field, but this property can be used
2729
      as a default array property.
2730

2731
      Parameters:
2732
        ARow: the row index (0-3). Range is checked with an assertion.
2733
        AColumn: the column index (0-3). Range is checked with an assertion. }
2734
    property Components[const ARow, AColumn: Integer]: Single read GetComponent write SetComponent; default;
2735
    {$ENDIF}
2736

2737
    { The determinant of this matrix. }
2738
    property Determinant: Single read GetDeterminant;
2739
  public
2740
    case Byte of
2741
      { Row or column vectors, depending on FM_COLUMN_MAJOR define }
2742
      0: (V: array [0..3] of TVector4);
2743

2744
      {$IFDEF FM_COLUMN_MAJOR}
2745
      { The four column vectors making up the matrix }
2746
      1: (C: array [0..3] of TVector4);
2747
      {$ELSE}
2748
      { The four row vectors making up the matrix }
2749
      2: (R: array [0..3] of TVector4);
2750
      {$ENDIF}
2751

2752
      { The elements of the matrix in row-major order }
2753
      3: (M: array [0..3, 0..3] of Single);
2754
      4: (m11, m12, m13, m14: Single;
2755
          m21, m22, m23, m24: Single;
2756
          m31, m32, m33, m34: Single;
2757
          m41, m42, m43, m44: Single);
2758
  end;
2759
  PMatrix4 = ^TMatrix4;
2760

2761
type
2762
  { Adds common constants of type TMatrix2 }
2763
  _TMatrix2Helper = record helper for TMatrix2
2764
  public const
2765
    Zero    : TMatrix2 = (M: ((0, 0), (0, 0)));
2766
    Identity: TMatrix2 = (M: ((1, 0), (0, 1)));
2767
  public
2768
    { Initializes the matrix with a 3x3 matrix. The upper-left corner of the
2769
      3x3 matrix is copied to the 2x2 matrix.
2770

2771
      Parameters:
2772
        AMatrix: the source 3x3 matrix. }
2773

2774
    procedure Init(const AMatrix: TMatrix3); overload;
2775

2776
    { Initializes the matrix with a 4x4 matrix. The upper-left corner of the
2777
      4x4 matrix is copied to the 3x3 matrix.
2778

2779
      Parameters:
2780
        AMatrix: the source 4x4 matrix. }
2781
    procedure Init(const AMatrix: TMatrix4); overload;
2782
  end;
2783

2784
type
2785
  { Adds common constants of type TMatrix3 }
2786
  _TMatrix3Helper = record helper for TMatrix3
2787
  public const
2788
    Zero    : TMatrix3 = (M: ((0, 0, 0), (0, 0, 0), (0, 0, 0)));
2789
    Identity: TMatrix3 = (M: ((1, 0, 0), (0, 1, 0), (0, 0, 1)));
2790
  public
2791
    { Initializes the matrix with a 4x4 matrix. The upper-left corner of the
2792
      4x4 matrix is copied to the 3x3 matrix.
2793

2794
      Parameters:
2795
        AMatrix: the source 4x4 matrix. }
2796
    procedure Init(const AMatrix: TMatrix4); overload;
2797
  end;
2798

2799
type
2800
  { Adds common constants of type TMatrix4 }
2801
  _TMatrix4Helper = record helper for TMatrix4
2802
  public const
2803
    Zero    : TMatrix4 = (M: ((0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)));
2804
    Identity: TMatrix4 = (M: ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)));
2805
  end;
2806

2807
type
2808
  { A quaternion.
2809

2810
    TQuaternion is compatible with TQuaternion3D in the Delphi RTL. You can
2811
    typecast between these two types or implicitly convert from one to the other
2812
    through assignment (eg. MyQuaternion := MyQuaternion3D). }
2813
  TQuaternion = record
2814
  {$REGION 'Internal Declarations'}
2815
  private
2816
    function GetLength: Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
2817
    function GetLengthSquared: Single; {$IFDEF FM_INLINE}inline;{$ENDIF}
2818
  {$ENDREGION 'Internal Declarations'}
2819
  public
2820
    { Initializes the quaternion to an identity quaternion. Sets the X, Y and
2821
      Z components to 0 and the W component to 1. }
2822
    procedure Init; overload; inline;
2823

2824
    { Sets the four components of the quaternion.
2825

2826
      Parameters:
2827
        AX: the X-component.
2828
        AY: the Y-component.
2829
        AZ: the Z-component.
2830
        AW: the W-component. }
2831
    procedure Init(const AX, AY, AZ, AW: Single); overload; inline;
2832

2833
    { Sets the quaternion from the given axis vector and the angle around that
2834
      axis in radians.
2835

2836
      Parameters:
2837
        AAxis: The axis.
2838
        AAngleRadians: The angle in radians. }
2839
    procedure Init(const AAxis: TVector3; const AAngleRadians: Single); overload;
2840

2841
    { Sets the quaternion to the given euler angles in radians.
2842

2843
      Parameters:
2844
        AYaw: the rotation around the Y axis in radians.
2845
        APitch: the rotation around the X axis in radians.
2846
        ARoll: the rotation around the Z axis in radians. }
2847
    procedure Init(const AYaw, APitch, ARoll: Single); overload;
2848

2849
    { Sets the quaternion from a matrix.
2850

2851
      Parameters:
2852
        AMatrix: the matrix. }
2853
    procedure Init(const AMatrix: TMatrix4); overload;
2854

2855
    { Creates a rotation matrix that represents this quaternion.
2856

2857
      Returns:
2858
        A rotation matrix that represents this quaternion. }
2859
    function ToMatrix: TMatrix4;
2860

2861
    { Implicitly converts a TQuaternion3D to a TQuaternion. }
2862
    class operator Implicit(const A: TQuaternion3D): TQuaternion; inline;
2863

2864
    { Implicitly converts a TQuaternion to a TQuaternion3D. }
2865
    class operator Implicit(const A: TQuaternion): TQuaternion3D; inline;
2866

2867
    { Adds to quaternions together.
2868

2869
      Returns:
2870
        A + B }
2871
    class operator Add(const A, B: TQuaternion): TQuaternion; {$IFDEF FM_INLINE}inline;{$ENDIF}
2872

2873
    { Multiplies a vector with a scalar value.
2874

2875
      Returns:
2876
        (A.X * B, A.Y * B, A.Z * B, A.W * B) }
2877
    class operator Multiply(const A: TQuaternion; const B: Single): TQuaternion; {$IFDEF FM_INLINE}inline;{$ENDIF}
2878

2879
    { Multiplies a vector with a scalar value.
2880

2881
      Returns:
2882
        (A * B.X, A * B.Y, A * B.Z, A * B.W) }
2883
    class operator Multiply(const A: Single; const B: TQuaternion): TQuaternion; {$IFDEF FM_INLINE}inline;{$ENDIF}
2884

2885
    { Multiplies two quaternions.
2886

2887
      Returns:
2888
        A * B }
2889
    class operator Multiply(const A, B: TQuaternion): TQuaternion; {$IFDEF FM_INLINE}inline;{$ENDIF}
2890

2891
    { Whether this is an identity quaternion.
2892

2893
      Returns:
2894
        True if X, Y and Z are exactly 0.0 and W is exactly 1.0 }
2895
    function IsIdentity: Boolean; overload; inline;
2896

2897
    { Whether this is an identity quaternion within a given margin of error.
2898

2899
      Parameters:
2900
        AErrorMargin: the allowed margin of error.
2901

2902
      Returns:
2903
        True if this is an identity quaternion within the error margin. }
2904
    function IsIdentity(const AErrorMargin: Single): Boolean; overload;
2905

2906
    { Calculates a normalized version of this quaternion.
2907

2908
      Returns:
2909
        The normalized quaternion of of this vector (with a length of 1).
2910

2911
      @bold(Note): for a faster, less accurate version, use NormalizeFast.
2912

2913
      @bold(Note): Does not change this quaternion. To update this quaternion
2914
      itself, use SetNormalized. }
2915
    function Normalize: TQuaternion; inline;
2916

2917
    { Normalizes this quaternion to a length of 1.
2918

2919
      @bold(Note): The SIMD optimized versions of this method use an
2920
      approximation, resulting in a very small error.
2921

2922
      @bold(Note): If you do not want to change this quaternion, but get a
2923
      normalized version instead, then use Normalize. }
2924
    procedure SetNormalized; inline;
2925

2926
    { Calculates a normalized version of this quaternion.
2927

2928
      Returns:
2929
        The normalized version of of this quaternion (with a length of 1).
2930

2931
      @bold(Note): this is an SIMD optimized version that uses an approximation,
2932
      resulting in a small error. For an accurate version, use Normalize.
2933

2934
      @bold(Note): Does not change this quaternion. To update this quaternion
2935
      itself, use SetNormalizedFast. }
2936
    function NormalizeFast: TQuaternion; {$IFDEF FM_INLINE}inline;{$ENDIF}
2937

2938
    { Normalizes this quaternion to a length of 1.
2939

2940
      @bold(Note): this is an SIMD optimized version that uses an approximation,
2941
      resulting in a small error. For an accurate version, use SetNormalized.
2942

2943
      @bold(Note): If you do not want to change this quaternion, but get a
2944
      normalized version instead, then use NormalizeFast. }
2945
    procedure SetNormalizedFast; {$IFDEF FM_INLINE}inline;{$ENDIF}
2946

2947
    { Creates a conjugate of the quaternion.
2948

2949
      Returns:
2950
        The conjugate (eg. (-X, -Y, -Z, W))
2951

2952
      @bold(Note): Does not change this quaterion. To update this quaterion
2953
      itself, use SetConjugate. }
2954
    function Conjugate: TQuaternion;
2955

2956
    { Conjugate this quaternion.
2957

2958
      @bold(Note): If you do not want to change this quaternion, but get a
2959
      conjugate version instead, then use Conjugate. }
2960
    procedure SetConjugate; inline;
2961

2962
    { The euclidean length of this quaternion.
2963

2964
      @bold(Note): If you only want to compare lengths of quaternion, you should
2965
      use LengthSquared instead, which is faster. }
2966
    property Length: Single read GetLength;
2967

2968
    { The squared length of the quaternion.
2969

2970
      @bold(Note): This property is faster than Length because it avoids
2971
      calculating a square root. It is useful for comparing lengths instead of
2972
      calculating actual lengths. }
2973
    property LengthSquared: Single read GetLengthSquared;
2974
  public
2975
    case Byte of
2976
      { X, Y, Z and W components of the quaternion }
2977
      0: (X, Y, Z, W: Single);
2978

2979
      { The four components of the quaternion. }
2980
      1: (C: array [0..3] of Single);
2981
  end;
2982

2983
type
2984
  { Adds common constants and functionality to TQuaternion }
2985
  _TQuaternionHelper = record helper for TQuaternion
2986
  public const
2987
    Identity: TQuaternion = (X: 0; Y: 0; Z: 0; W: 1);
2988
  end;
2989

2990
type
2991
  { A 2-dimensional vector that uses integer components instead of
2992
    floating-point components.
2993

2994
    TIVector2 is compatible with TPoint in the Delphi RTL. You can typecast
2995
    between these two types or implicitly convert from one to the other through
2996
    assignment (eg. MyIVector := MyPoint). }
2997
  TIVector2 = record
2998
  {$REGION 'Internal Declarations'}
2999
  private
3000
    function GetComponent(const AIndex: Integer): Integer; inline;
3001
    procedure SetComponent(const AIndex: Integer; const Value: Integer); inline;
3002
  {$ENDREGION 'Internal Declarations'}
3003
  public
3004
    { Sets the two elements (X and Y) to 0. }
3005
    procedure Init; overload; inline;
3006

3007
    { Sets the two elements (X and Y) to A.
3008

3009
      Parameters:
3010
        A: the value to set the two elements to. }
3011
    procedure Init(const A: Integer); overload; inline;
3012

3013
    { Sets the two elements (X and Y) to A1 and A2 respectively.
3014

3015
      Parameters:
3016
        A1: the value to set the first element to.
3017
        A2: the value to set the second element to. }
3018
    procedure Init(const A1, A2: Integer); overload; inline;
3019

3020
    { Implicitly converts a TPoint to a TIVector2. }
3021
    class operator Implicit(const A: TPoint): TIVector2; inline;
3022

3023
    { Implicitly converts a TQuaternion to a TPoint. }
3024
    class operator Implicit(const A: TIVector2): TPoint; inline;
3025

3026
    { Checks two vectors for equality.
3027

3028
      Returns:
3029
        True if the two vectors match each other. }
3030
    class operator Equal(const A, B: TIVector2): Boolean; inline;
3031

3032
    { Checks two vectors for inequality.
3033

3034
      Returns:
3035
        True if the two vectors are not equal. }
3036
    class operator NotEqual(const A, B: TIVector2): Boolean; inline;
3037

3038
    { Negates a vector.
3039

3040
      Returns:
3041
        The negative value of a vector (eg. (-A.X, -A.Y)) }
3042
    class operator Negative(const A: TIVector2): TIVector2; inline;
3043

3044
    { Adds a scalar value to a vector.
3045

3046
      Returns:
3047
        (A.X + B, A.Y + B) }
3048
    class operator Add(const A: TIVector2; const B: Integer): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3049

3050
    { Adds a vector to a scalar value.
3051

3052
      Returns:
3053
        (A + B.X, A + B.Y) }
3054
    class operator Add(const A: Integer; const B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3055

3056
    { Adds two vectors.
3057

3058
      Returns:
3059
        (A.X + B.X, A.Y + B.Y) }
3060
    class operator Add(const A, B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3061

3062
    { Subtracts a scalar value from a vector.
3063

3064
      Returns:
3065
        (A.X - B, A.Y - B) }
3066
    class operator Subtract(const A: TIVector2; const B: Integer): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3067

3068
    { Subtracts a vector from a scalar value.
3069

3070
      Returns:
3071
        (A - B.X, A - B.Y) }
3072
    class operator Subtract(const A: Integer; const B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3073

3074
    { Subtracts two vectors.
3075

3076
      Returns:
3077
        (A.X - B.X, A.Y - B.Y) }
3078
    class operator Subtract(const A, B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3079

3080
    { Multiplies a vector with a scalar value.
3081

3082
      Returns:
3083
        (A.X * B, A.Y * B) }
3084
    class operator Multiply(const A: TIVector2; const B: Integer): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3085

3086
    { Multiplies a scalar value with a vector.
3087

3088
      Returns:
3089
        (A * B.X, A * B.Y) }
3090
    class operator Multiply(const A: Integer; const B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3091

3092
    { Multiplies two vectors component-wise.
3093

3094
      Returns:
3095
        (A.X * B.X, A.Y * B.Y) }
3096
    class operator Multiply(const A, B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3097

3098
    { Divides a vector by a scalar value.
3099

3100
      Returns:
3101
        (A.X div B, A.Y div B) }
3102
    class operator IntDivide(const A: TIVector2; const B: Integer): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3103

3104
    { Divides a scalar value by a vector.
3105

3106
      Returns:
3107
        (A div B.X, A div B.Y) }
3108
    class operator IntDivide(const A: Integer; const B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3109

3110
    { Divides two vectors component-wise.
3111

3112
      Returns:
3113
        (A.X div B.X, A.Y div B.Y) }
3114
    class operator IntDivide(const A, B: TIVector2): TIVector2; {$IFDEF FM_INLINE}inline;{$ENDIF}
3115

3116
    { Whether this is a zero vector.
3117

3118
      Returns:
3119
        True if X and Y are 0 }
3120
    function IsZero: Boolean; inline;
3121

3122
    { Returns the components of the vector.
3123
      This is identical to accessing the C-field, but this property can be used
3124
      as a default array property.
3125

3126
      Parameters:
3127
        AIndex: index of the component to return (0 or 1). Range is checked
3128
          with an assertion. }
3129
    property Components[const AIndex: Integer]: Integer read GetComponent write SetComponent; default;
3130
  public
3131
    case Byte of
3132
      { X and Y components of the vector. Aliases for C[0] and C[1]. }
3133
      0: (X, Y: Integer);
3134

3135
      { Red and Green components of the vector. Aliases for C[0] and C[1]. }
3136
      1: (R, G: Integer);
3137

3138
      { S and T components of the vector. Aliases for C[0] and C[1]. }
3139
      2: (S, T: Integer);
3140

3141
      { The two components of the vector. }
3142
      3: (C: array [0..1] of Integer);
3143
  end;
3144
  PIVector2 = ^TIVector2;
3145

3146
type
3147
  { Adds common constants of type TVector2 }
3148
  _TVector2Helper = record helper for TVector2
3149
  public const
3150
    Zero : TVector2 = (X: 0; Y: 0);
3151
    One  : TVector2 = (X: 1; Y: 1);
3152
    UnitX: TVector2 = (X: 1; Y: 0);
3153
    UnitY: TVector2 = (X: 0; Y: 1);
3154
  public
3155
    { Rounds the components of the vector towards negative infinity.
3156

3157
      Returns:
3158
        The rounded vector. }
3159
    function Floor: TIVector2; inline;
3160

3161
    { Rounds the components of the vector towards positive infinity.
3162

3163
      Returns:
3164
        The rounded vector. }
3165
    function Ceiling: TIVector2; inline;
3166

3167
    { Rounds the components of the vector towards 0.
3168

3169
      Returns:
3170
        The rounded vector. }
3171
    function Truncate: TIVector2; inline;
3172

3173
    { Rounds the components of the vector towards the nearest integer.
3174

3175
      Returns:
3176
        The rounded vector.
3177

3178
      If a component is exactly between two integer values (if the fraction is
3179
      0.5), then it is set to the even number }
3180
    function Round: TIVector2; inline;
3181
  end;
3182

3183
type
3184
  { A 3-dimensional vector that uses integer components instead of
3185
    floating-point components. }
3186
  TIVector3 = record
3187
  {$REGION 'Internal Declarations'}
3188
  private
3189
    function GetComponent(const AIndex: Integer): Integer; inline;
3190
    procedure SetComponent(const AIndex: Integer; const Value: Integer); inline;
3191
  {$ENDREGION 'Internal Declarations'}
3192
  public
3193
    { Sets the three elements (X, Y and Z) to 0. }
3194
    procedure Init; overload; inline;
3195

3196
    { Sets the three elements (X, Y and Z) to A.
3197

3198
      Parameters:
3199
        A: the value to set the three elements to. }
3200
    procedure Init(const A: Integer); overload; inline;
3201

3202
    { Sets the three elements (X, Y and Z) to A1, A2 and A3 respectively.
3203

3204
      Parameters:
3205
        A1: the value to set the first element to.
3206
        A2: the value to set the second element to.
3207
        A3: the value to set the third element to. }
3208
    procedure Init(const A1, A2, A3: Integer); overload; inline;
3209

3210
    { Checks two vectors for equality.
3211

3212
      Returns:
3213
        True if the two vectors match each other exactly. }
3214
    class operator Equal(const A, B: TIVector3): Boolean; inline;
3215

3216
    { Checks two vectors for inequality.
3217

3218
      Returns:
3219
        True if the two vectors are not equal. }
3220
    class operator NotEqual(const A, B: TIVector3): Boolean; inline;
3221

3222
    { Negates a vector.
3223

3224
      Returns:
3225
        The negative value of a vector (eg. (-A.X, -A.Y, -A.Z)) }
3226
    class operator Negative(const A: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3227

3228
    { Adds a scalar value to a vector.
3229

3230
      Returns:
3231
        (A.X + B, A.Y + B, A.Z + B) }
3232
    class operator Add(const A: TIVector3; const B: Integer): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3233

3234
    { Adds a vector to a scalar value.
3235

3236
      Returns:
3237
        (A + B.X, A + B.Y, A + B.Z) }
3238
    class operator Add(const A: Integer; const B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3239

3240
    { Adds two vectors.
3241

3242
      Returns:
3243
        (A.X + B.X, A.Y + B.Y, A.Z + B.Z) }
3244
    class operator Add(const A, B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3245

3246
    { Subtracts a scalar value from a vector.
3247

3248
      Returns:
3249
        (A.X - B, A.Y - B, A.Z - B) }
3250
    class operator Subtract(const A: TIVector3; const B: Integer): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3251

3252
    { Subtracts a vector from a scalar value.
3253

3254
      Returns:
3255
        (A - B.X, A - B.Y, A - B.Z) }
3256
    class operator Subtract(const A: Integer; const B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3257

3258
    { Subtracts two vectors.
3259

3260
      Returns:
3261
        (A.X - B.X, A.Y - B.Y, A.Z - B.Z) }
3262
    class operator Subtract(const A, B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3263

3264
    { Multiplies a vector with a scalar value.
3265

3266
      Returns:
3267
        (A.X * B, A.Y * B, A.Z * B) }
3268
    class operator Multiply(const A: TIVector3; const B: Integer): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3269

3270
    { Multiplies a scalar value with a vector.
3271

3272
      Returns:
3273
        (A * B.X, A * B.Y, A * B.Z) }
3274
    class operator Multiply(const A: Integer; const B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3275

3276
    { Multiplies two vectors component-wise.
3277

3278
      Returns:
3279
        (A.X * B.X, A.Y * B.Y, A.Z * B.Z) }
3280
    class operator Multiply(const A, B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3281

3282
    { Divides a vector by a scalar value.
3283

3284
      Returns:
3285
        (A.X div B, A.Y div B, A.Z div B) }
3286
    class operator IntDivide(const A: TIVector3; const B: Integer): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3287

3288
    { Divides a scalar value by a vector.
3289

3290
      Returns:
3291
        (A div B.X, A div B.Y, A div B.Z) }
3292
    class operator IntDivide(const A: Integer; const B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3293

3294
    { Divides two vectors component-wise.
3295

3296
      Returns:
3297
        (A.X div B.X, A.Y div B.Y, A.Z div B.Z) }
3298
    class operator IntDivide(const A, B: TIVector3): TIVector3; {$IFDEF FM_INLINE}inline;{$ENDIF}
3299

3300
    { Whether this is a zero vector.
3301

3302
      Returns:
3303
        True if X, Y and Z are 0 }
3304
    function IsZero: Boolean; inline;
3305

3306
    { Returns the components of the vector.
3307
      This is identical to accessing the C-field, but this property can be used
3308
      as a default array property.
3309

3310
      Parameters:
3311
        AIndex: index of the component to return (0-2). Range is checked
3312
          with an assertion. }
3313
    property Components[const AIndex: Integer]: Integer read GetComponent write SetComponent; default;
3314
  public
3315
    case Byte of
3316
      { X, Y and Z components of the vector. Aliases for C[0], C[1] and C[2]. }
3317
      0: (X, Y, Z: Integer);
3318

3319
      { Red, Green and Blue components of the vector. Aliases for C[0], C[1]
3320
        and C[2]. }
3321
      1: (R, G, B: Integer);
3322

3323
      { S, T and P components of the vector. Aliases for C[0], C[1] and C[2]. }
3324
      2: (S, T, P: Integer);
3325

3326
      { The three components of the vector. }
3327
      3: (C: array [0..2] of Integer);
3328
  end;
3329
  PIVector3 = ^TIVector3;
3330

3331
type
3332
  { Adds common constants of type TVector3 }
3333
  _TVector3Helper = record helper for TVector3
3334
  public const
3335
    Zero : TVector3 = (X: 0; Y: 0; Z: 0);
3336
    One  : TVector3 = (X: 1; Y: 1; Z: 1);
3337
    UnitX: TVector3 = (X: 1; Y: 0; Z: 0);
3338
    UnitY: TVector3 = (X: 0; Y: 1; Z: 0);
3339
    UnitZ: TVector3 = (X: 0; Y: 0; Z: 1);
3340
  public
3341
    { Rounds the components of the vector towards negative infinity.
3342

3343
      Returns:
3344
        The rounded vector. }
3345
    function Floor: TIVector3; inline;
3346

3347
    { Rounds the components of the vector towards positive infinity.
3348

3349
      Returns:
3350
        The rounded vector. }
3351
    function Ceiling: TIVector3; inline;
3352

3353
    { Rounds the components of the vector towards 0.
3354

3355
      Returns:
3356
        The rounded vector. }
3357
    function Truncate: TIVector3; inline;
3358

3359
    { Rounds the components of the vector towards the nearest integer.
3360

3361
      Returns:
3362
        The rounded vector.
3363

3364
      If a component is exactly between two integer values (if the fraction is
3365
      0.5), then it is set to the even number }
3366
    function Round: TIVector3; inline;
3367
  end;
3368

3369
type
3370
  { A 4-dimensional vector that uses integer components instead of
3371
    floating-point components. }
3372
  TIVector4 = record
3373
  {$REGION 'Internal Declarations'}
3374
  private
3375
    function GetComponent(const AIndex: Integer): Integer; inline;
3376
    procedure SetComponent(const AIndex: Integer; const Value: Integer); inline;
3377
  {$ENDREGION 'Internal Declarations'}
3378
  public
3379
    { Sets the four elements (X, Y, Z and W) to 0. }
3380
    procedure Init; overload; inline;
3381

3382
    { Sets the four elements (X, Y, Z and W) to A.
3383

3384
      Parameters:
3385
        A: the value to set the three elements to. }
3386
    procedure Init(const A: Integer); overload; inline;
3387

3388
    { Sets the four elements (X, Y, Z and W) to A1, A2, A3 and A4 respectively.
3389

3390
      Parameters:
3391
        A1: the value to set the first element to.
3392
        A2: the value to set the second element to.
3393
        A3: the value to set the third element to.
3394
        A4: the value to set the fourth element to. }
3395
    procedure Init(const A1, A2, A3, A4: Integer); overload; inline;
3396

3397
    { Checks two vectors for equality.
3398

3399
      Returns:
3400
        True if the two vectors match each other. }
3401
    class operator Equal(const A, B: TIVector4): Boolean; inline;
3402

3403
    { Checks two vectors for inequality.
3404

3405
      Returns:
3406
        True if the two vectors are not equal. }
3407
    class operator NotEqual(const A, B: TIVector4): Boolean; inline;
3408

3409
    { Negates a vector.
3410

3411
      Returns:
3412
        The negative value of a vector (eg. (-A.X, -A.Y, -A.Z, -A.W)) }
3413
    class operator Negative(const A: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3414

3415
    { Adds a scalar value to a vector.
3416

3417
      Returns:
3418
        (A.X + B, A.Y + B, A.Z + B, A.W + B) }
3419
    class operator Add(const A: TIVector4; const B: Integer): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3420

3421
    { Adds a vector to a scalar value.
3422

3423
      Returns:
3424
        (A + B.X, A + B.Y, A + B.Z, A + B.W) }
3425
    class operator Add(const A: Integer; const B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3426

3427
    { Adds two vectors.
3428

3429
      Returns:
3430
        (A.X + B.X, A.Y + B.Y, A.Z + B.Z, A.W + B.W) }
3431
    class operator Add(const A, B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3432

3433
    { Subtracts a scalar value from a vector.
3434

3435
      Returns:
3436
        (A.X - B, A.Y - B, A.Z - B, A.W - B) }
3437
    class operator Subtract(const A: TIVector4; const B: Integer): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3438

3439
    { Subtracts a vector from a scalar value.
3440

3441
      Returns:
3442
        (A - B.X, A - B.Y, A - B.Z, A - B.W) }
3443
    class operator Subtract(const A: Integer; const B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3444

3445
    { Subtracts two vectors.
3446

3447
      Returns:
3448
        (A.X - B.X, A.Y - B.Y, A.Z - B.Z, A.W - B.W) }
3449
    class operator Subtract(const A, B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3450

3451
    { Multiplies a vector with a scalar value.
3452

3453
      Returns:
3454
        (A.X * B, A.Y * B, A.Z * B, A.W * B) }
3455
    class operator Multiply(const A: TIVector4; const B: Integer): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3456

3457
    { Multiplies a scalar value with a vector.
3458

3459
      Returns:
3460
        (A * B.X, A * B.Y, A * B.Z, A * B.W) }
3461
    class operator Multiply(const A: Integer; const B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3462

3463
    { Multiplies two vectors component-wise.
3464

3465
      Returns:
3466
        (A.X * B.X, A.Y * B.Y, A.Z * B.Z, A.W * B.W) }
3467
    class operator Multiply(const A, B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3468

3469
    { Divides a vector by a scalar value.
3470

3471
      Returns:
3472
        (A.X div B, A.Y div B, A.Z div B, A.W div B) }
3473
    class operator IntDivide(const A: TIVector4; const B: Integer): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3474

3475
    { Divides a scalar value by a vector.
3476

3477
      Returns:
3478
        (A div B.X, A div B.Y, A div B.Z, A div B.W) }
3479
    class operator IntDivide(const A: Integer; const B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3480

3481
    { Divides two vectors component-wise.
3482

3483
      Returns:
3484
        (A.X div B.X, A.Y div B.Y, A.Z div B.Z, A.W div B.W) }
3485
    class operator IntDivide(const A, B: TIVector4): TIVector4; {$IFDEF FM_INLINE}inline;{$ENDIF}
3486

3487
    { Whether this is a zero vector.
3488

3489
      Returns:
3490
        True if X, Y, Z and W are 0 }
3491
    function IsZero: Boolean; inline;
3492

3493
    { Returns the components of the vector.
3494
      This is identical to accessing the C-field, but this property can be used
3495
      as a default array property.
3496

3497
      Parameters:
3498
        AIndex: index of the component to return (0-3). Range is checked
3499
          with an assertion. }
3500
    property Components[const AIndex: Integer]: Integer read GetComponent write SetComponent; default;
3501
  public
3502
    case Byte of
3503
      { X, Y, Z and W components of the vector. Aliases for C[0], C[1], C[2]
3504
        and C[3]. }
3505
      0: (X, Y, Z, W: Integer);
3506

3507
      { Red, Green, Blue and Alpha components of the vector. Aliases for C[0],
3508
        C[1], C[2] and C[3]. }
3509
      1: (R, G, B, A: Integer);
3510

3511
      { S, T, P and Q components of the vector. Aliases for C[0], C[1], C[2] and
3512
        C[3]. }
3513
      2: (S, T, P, Q: Integer);
3514

3515
      { The four components of the vector. }
3516
      3: (C: array [0..3] of Integer);
3517
  end;
3518
  PIVector4 = ^TIVector4;
3519

3520
type
3521
  { Adds common constants of type TVector4 }
3522
  _TVector4Helper = record helper for TVector4
3523
  public const
3524
    Zero : TVector4 = (X: 0; Y: 0; Z: 0; W: 0);
3525
    One  : TVector4 = (X: 1; Y: 1; Z: 1; W: 1);
3526
    UnitX: TVector4 = (X: 1; Y: 0; Z: 0; W: 0);
3527
    UnitY: TVector4 = (X: 0; Y: 1; Z: 0; W: 0);
3528
    UnitZ: TVector4 = (X: 0; Y: 0; Z: 1; W: 0);
3529
    UnitW: TVector4 = (X: 0; Y: 0; Z: 0; W: 1);
3530
  public
3531
    { Rounds the components of the vector towards negative infinity.
3532

3533
      Returns:
3534
        The rounded vector. }
3535
    function Floor: TIVector4; inline;
3536

3537
    { Rounds the components of the vector towards positive infinity.
3538

3539
      Returns:
3540
        The rounded vector. }
3541
    function Ceiling: TIVector4; inline;
3542

3543
    { Rounds the components of the vector towards 0.
3544

3545
      Returns:
3546
        The rounded vector. }
3547
    function Truncate: TIVector4; inline;
3548

3549
    { Rounds the components of the vector towards the nearest integer.
3550

3551
      Returns:
3552
        The rounded vector.
3553

3554
      If a component is exactly between two integer values (if the fraction is
3555
      0.5), then it is set to the even number }
3556
    function Round: TIVector4; inline;
3557
  end;
3558

3559
{******************************************************}
3560
{* Helper functions for creating vectors and matrices *}
3561
{* Note that these are (much) less efficient than the *}
3562
{* respective Init methods                            *}
3563
{******************************************************}
3564

3565
{***** TVector2 *****}
3566

3567
{ Creates a 2D zero-vector.
3568

3569
  @bold(Note): it is more efficient to use TVector2.Init instead. }
3570
function Vector2: TVector2; overload; inline;
3571

3572
{ Creates a 2D vector with the two elements (X and Y) set to A.
3573

3574
  Parameters:
3575
    A: the value to set the two elements to.
3576

3577
  @bold(Note): it is more efficient to use TVector2.Init instead. }
3578
function Vector2(const A: Single): TVector2; overload; inline;
3579

3580
{ Creates a 2D vector with the two elements (X and Y) set to A1 and A2
3581
  respectively.
3582

3583
  Parameters:
3584
    A1: the value to set the first element to.
3585
    A2: the value to set the second element to.
3586

3587
  @bold(Note): it is more efficient to use TVector2.Init instead. }
3588
function Vector2(const A1, A2: Single): TVector2; overload; inline;
3589

3590
{ Creates a 2D vector using the first to elements (X and Y) of a 3D vector.
3591

3592
  Parameters:
3593
    AVector: the source vector
3594

3595
  @bold(Note): it is more efficient to use TVector2.Init instead. }
3596
function Vector2(const AVector: TVector3): TVector2; overload; inline;
3597

3598
{ Creates a 2D vector using the first two elements (X and Y) of a 4D vector.
3599

3600
  Parameters:
3601
    AVector: the source vector
3602

3603
  @bold(Note): it is more efficient to use TVector2.Init instead. }
3604
function Vector2(const AVector: TVector4): TVector2; overload; inline;
3605

3606
{***** TVector3 *****}
3607

3608
{ Creates a 3D zero-vector.
3609

3610
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3611
function Vector3: TVector3; overload;
3612

3613
{ Creates a 3D vector with the three elements (X, Y and Z) set to A.
3614

3615
  Parameters:
3616
    A: the value to set the three elements to.
3617

3618
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3619
function Vector3(const A: Single): TVector3; overload;
3620

3621
{ Creates a 3D vector with the three elements (X, Y and Z) set to A1, A2 and A3
3622
  respectively.
3623

3624
  Parameters:
3625
    A1: the value to set the first element to.
3626
    A2: the value to set the second element to.
3627
    A3: the value to set the third element to.
3628

3629
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3630
function Vector3(const A1, A2, A3: Single): TVector3; overload;
3631

3632
{ Creates a 3D vector with the first two elements from a 2D vector, and the
3633
  third element from a scalar.
3634

3635
  Parameters:
3636
    A1: the vector to use for the first two elements.
3637
    A2: the value to set the third element to.
3638

3639
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3640
function Vector3(const A1: TVector2; const A2: Single): TVector3; overload;
3641

3642
{ Creates a 3D vector with the first element from a scaler, and the last two
3643
  elements from a 2D vector.
3644

3645
  Parameters:
3646
    A1: the value to set the first element to.
3647
    A2: the vector to use for the last two elements.
3648

3649
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3650
function Vector3(const A1: Single; const A2: TVector2): TVector3; overload;
3651

3652
{ Creates a 3D vector using the first three elements (X, Y and Z) of a 4D vector.
3653

3654
  Parameters:
3655
    AVector: the source vector
3656

3657
  @bold(Note): it is more efficient to use TVector3.Init instead. }
3658
function Vector3(const AVector: TVector4): TVector3; overload;
3659

3660
{***** TVector4 *****}
3661

3662
{ Creates a 4D zero-vector.
3663

3664
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3665
function Vector4: TVector4; overload;
3666

3667
{ Creates a 4D vector with the four elements (X, Y, Z and W) set to A.
3668

3669
  Parameters:
3670
    A: the value to set the four elements to.
3671

3672
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3673
function Vector4(const A: Single): TVector4; overload;
3674

3675
{ Creates a 4D vector with the four elements (X, Y, Z and W) set to A1, A2, A3
3676
  and A4 respectively.
3677

3678
  Parameters:
3679
    A1: the value to set the first element to.
3680
    A2: the value to set the second element to.
3681
    A3: the value to set the third element to.
3682
    A4: the value to set the fourth element to.
3683

3684
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3685
function Vector4(const A1, A2, A3, A4: Single): TVector4; overload;
3686

3687
{ Creates a 4D vector with the first two elements from a 2D vector, and the last
3688
  two elements from two scalars.
3689

3690
  Parameters:
3691
    A1: the vector to use for the first two elements.
3692
    A2: the value to set the third element to.
3693
    A3: the value to set the fourth element to.
3694

3695
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3696
function Vector4(const A1: TVector2; const A2, A3: Single): TVector4; overload;
3697

3698
{ Creates a 4D vector with the first and last elements from two scalars, and the
3699
  middle two elements from a 2D vector.
3700

3701
  Parameters:
3702
    A1: the value to set the first element to.
3703
    A2: the vector to use for the second and third elements.
3704
    A3: the value to set the fourth element to.
3705

3706
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3707
function Vector4(const A1: Single; const A2: TVector2; const A3: Single): TVector4; overload;
3708

3709
{ Creates a 4D vector with the first two elements from two scalars and the last
3710
  two elements from a 2D vector.
3711

3712
  Parameters:
3713
    A1: the value to set the first element to.
3714
    A2: the value to set the second element to.
3715
    A3: the vector to use for the last two elements.
3716

3717
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3718
function Vector4(const A1, A2: Single; const A3: TVector2): TVector4; overload;
3719

3720
{ Creates a 4D vector with the first two elements and last two elements from two
3721
  2D vectors.
3722

3723
  Parameters:
3724
    A1: the vector to use for the first two elements.
3725
    A2: the vector to use for the last two elements.
3726

3727
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3728
function Vector4(const A1, A2: TVector2): TVector4; overload;
3729

3730
{ Creates a 4D vector with the first three elements from a 3D vector, and the
3731
  fourth element from a scalar.
3732

3733
  Parameters:
3734
    A1: the vector to use for the first three elements.
3735
    A2: the value to set the fourth element to.
3736

3737
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3738
function Vector4(const A1: TVector3; const A2: Single): TVector4; overload;
3739

3740
{ Creates a 4D vector with the first element from a scaler, and the last three
3741
  elements from a 3D vector.
3742

3743
  Parameters:
3744
    A1: the value to set the first element to.
3745
    A2: the vector to use for the last three elements.
3746

3747
  @bold(Note): it is more efficient to use TVector4.Init instead. }
3748
function Vector4(const A1: Single; const A2: TVector3): TVector4; overload;
3749

3750
{***** TQuaternion *****}
3751

3752
{ Creates an identity quaternion (with X, Y and Z set to 0 and W set to 1).
3753

3754
  @bold(Note): it is more efficient to use TQuaternion.Init instead. }
3755
function Quaternion: TQuaternion; overload;
3756

3757
{ Creates a quaternion with the given components.
3758

3759
  Parameters:
3760
    AX: the X-component.
3761
    AY: the Y-component.
3762
    AZ: the Z-component.
3763
    AW: the W-component.
3764

3765
  @bold(Note): it is more efficient to use TQuaternion.Init instead. }
3766
function Quaternion(const AX, AY, AZ, AW: Single): TQuaternion; overload;
3767

3768
{ Creates a quaternion from the given axis vector and the angle around that
3769
  axis in radians.
3770

3771
  Parameters:
3772
    AAxis: The axis.
3773
    AAngleRadians: The angle in radians.
3774

3775
  @bold(Note): it is more efficient to use TQuaternion.Init instead. }
3776
function Quaternion(const AAxis: TVector3; const AAngleRadians: Single): TQuaternion; overload;
3777

3778
{***** TMatrix2 *****}
3779

3780
{ Creates a 2x2 identity matrix
3781

3782
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3783
function Matrix2: TMatrix2; overload;
3784

3785
{ Creates a 2x2 matrix fill with zeros and sets the diagonal.
3786

3787
  Parameters:
3788
    ADiagonal: the value to use for the diagonal. Use 1 for an identity matrix.
3789

3790
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3791
function Matrix2(const ADiagonal: Single): TMatrix2; overload;
3792

3793
{ Creates a 2x2 matrix using two row vectors.
3794

3795
  Parameters:
3796
    ARow0: the first row of the matrix.
3797
    ARow1: the second row of the matrix.
3798

3799
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3800
function Matrix2(const ARow0, ARow1: TVector2): TMatrix2; overload;
3801

3802
{ Creates a 2x2 matrix with explicit values.
3803

3804
  Parameters:
3805
    A11-A12: the values of the matrix elements, in row-major order.
3806

3807
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3808
function Matrix2(const A11, A12, A21, A22: Single): TMatrix2; overload;
3809

3810
{ Creates a 2x2 using the top-left corner of a 3x3 matrix.
3811
  The remaining values of the source matrix are not used.
3812

3813
  Parameters:
3814
    AMatrix: the source 3x3 matrix.
3815

3816
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3817
function Matrix2(const AMatrix: TMatrix3): TMatrix2; overload;
3818

3819
{ Creates a 2x2 using the top-left corner of a 4x4 matrix.
3820
  The remaining values of the source matrix are not used.
3821

3822
  Parameters:
3823
    AMatrix: the source 4x4  matrix.
3824

3825
  @bold(Note): it is more efficient to use TMatrix2.Init instead. }
3826
function Matrix2(const AMatrix: TMatrix4): TMatrix2; overload;
3827

3828
{***** TMatrix3 *****}
3829

3830
{ Creates a 3x3 identity matrix
3831

3832
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3833
function Matrix3: TMatrix3; overload;
3834

3835
{ Creates a 3x3 matrix fill with zeros and sets the diagonal.
3836

3837
  Parameters:
3838
    ADiagonal: the value to use for the diagonal. Use 1 for an identity matrix.
3839

3840
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3841
function Matrix3(const ADiagonal: Single): TMatrix3; overload;
3842

3843
{ Creates a 3x3 matrix using three row vectors.
3844

3845
  Parameters:
3846
    ARow0: the first row of the matrix.
3847
    ARow1: the second row of the matrix.
3848
    ARow2: the third row of the matrix.
3849

3850
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3851
function Matrix3(const ARow0, ARow1, ARow2: TVector3): TMatrix3; overload;
3852

3853
{ Creates a 3x3 matrix with explicit values.
3854

3855
  Parameters:
3856
    A11-A33: the values of the matrix elements, in row-major order.
3857

3858
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3859
function Matrix3(const A11, A12, A13, A21, A22, A23, A31, A32, A33: Single): TMatrix3; overload;
3860

3861
{ Creates a 3x3 matrix by copying a 2x2 matrix to the top-left corner of the 3x3
3862
  matrix, and setting the remaining elements according to an identity matrix.
3863

3864
  Parameters:
3865
    AMatrix: the source 2x2 matrix.
3866

3867
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3868
function Matrix3(const AMatrix: TMatrix2): TMatrix3; overload;
3869

3870
{ Creates a 3x3 using the top-left corner of a 4x4 matrix.
3871
  The remaining values of the source matrix are not used.
3872

3873
  Parameters:
3874
    AMatrix: the 4x4 source matrix.
3875

3876
  @bold(Note): it is more efficient to use TMatrix3.Init instead. }
3877
function Matrix3(const AMatrix: TMatrix4): TMatrix3; overload;
3878

3879
{***** TMatrix4 *****}
3880

3881
{ Creates a 4x4 identity matrix
3882

3883
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3884
function Matrix4: TMatrix4; overload;
3885

3886
{ Creates a 4x4 matrix fill with zeros and sets the diagonal.
3887

3888
  Parameters:
3889
    ADiagonal: the value to use for the diagonal. Use 1 for an identity matrix.
3890

3891
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3892
function Matrix4(const ADiagonal: Single): TMatrix4; overload;
3893

3894
{ Creates a 4x4 matrix using four row vectors.
3895

3896
  Parameters:
3897
    ARow0: the first row of the matrix.
3898
    ARow1: the second row of the matrix.
3899
    ARow2: the third row of the matrix.
3900
    ARow3: the fourth row of the matrix.
3901

3902
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3903
function Matrix4(const ARow0, ARow1, ARow2, ARow3: TVector4): TMatrix4; overload;
3904

3905
{ Creates a 4x4 matrix with explicit values.
3906

3907
  Parameters:
3908
    A11-A44: the values of the matrix elements, in row-major order.
3909

3910
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3911
function Matrix4(const A11, A12, A13, A14, A21, A22, A23, A24, A31, A32, A33,
3912
  A34, A41, A42, A43, A44: Single): TMatrix4; overload;
3913

3914
{ Creates a 4x4 matrix by copying a 2x2 matrix to the top-left corner of the 4x4
3915
  matrix, and setting the remaining elements according to an identity matrix.
3916

3917
  Parameters:
3918
    AMatrix: the source 2x2 matrix.
3919

3920
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3921
function Matrix4(const AMatrix: TMatrix2): TMatrix4; overload;
3922

3923
{ Creates a 4x4 matrix by copying a 3x3 matrix to the top-left corner of the 4x4
3924
  matrix, and setting the remaining elements according to an identity matrix.
3925

3926
  Parameters:
3927
    AMatrix: the source 3x3 matrix.
3928

3929
  @bold(Note): it is more efficient to use TMatrix4.Init instead. }
3930
function Matrix4(const AMatrix: TMatrix3): TMatrix4; overload;
3931

3932
{***** TIVector2 *****}
3933

3934
{ Creates a 2D zero-vector.
3935

3936
  @bold(Note): it is more efficient to use TIVector2.Init instead. }
3937
function IVector2: TIVector2; overload; inline;
3938

3939
{ Creates a 2D vector with the two elements (X and Y) set to A.
3940

3941
  Parameters:
3942
    A: the value to set the two elements to.
3943

3944
  @bold(Note): it is more efficient to use TIVector2.Init instead. }
3945
function IVector2(const A: Integer): TIVector2; overload; inline;
3946

3947
{ Creates a 2D vector with the two elements (X and Y) set to A1 and A2
3948
  respectively.
3949

3950
  Parameters:
3951
    A1: the value to set the first element to.
3952
    A2: the value to set the second element to.
3953

3954
  @bold(Note): it is more efficient to use TIVector2.Init instead. }
3955
function IVector2(const A1, A2: Integer): TIVector2; overload; inline;
3956

3957
{***** TIVector3 *****}
3958

3959
{ Creates a 3D zero-vector.
3960

3961
  @bold(Note): it is more efficient to use TIVector3.Init instead. }
3962
function IVector3: TIVector3; overload;
3963

3964
{ Creates a 3D vector with the three elements (X, Y and Z) set to A.
3965

3966
  Parameters:
3967
    A: the value to set the three elements to.
3968

3969
  @bold(Note): it is more efficient to use TIVector3.Init instead. }
3970
function IVector3(const A: Integer): TIVector3; overload;
3971

3972
{ Creates a 3D vector with the three elements (X, Y and Z) set to A1, A2 and A3
3973
  respectively.
3974

3975
  Parameters:
3976
    A1: the value to set the first element to.
3977
    A2: the value to set the second element to.
3978
    A3: the value to set the third element to.
3979

3980
  @bold(Note): it is more efficient to use TIVector3.Init instead. }
3981
function IVector3(const A1, A2, A3: Integer): TIVector3; overload;
3982

3983
{***** TIVector4 *****}
3984

3985
{ Creates a 4D zero-vector.
3986

3987
  @bold(Note): it is more efficient to use TIVector4.Init instead. }
3988
function IVector4: TIVector4; overload;
3989

3990
{ Creates a 4D vector with the four elements (X, Y, Z and W) set to A.
3991

3992
  Parameters:
3993
    A: the value to set the four elements to.
3994

3995
  @bold(Note): it is more efficient to use TIVector4.Init instead. }
3996
function IVector4(const A: Integer): TIVector4; overload;
3997

3998
{ Creates a 4D vector with the four elements (X, Y, Z and W) set to A1, A2, A3
3999
  and A4 respectively.
4000

4001
  Parameters:
4002
    A1: the value to set the first element to.
4003
    A2: the value to set the second element to.
4004
    A3: the value to set the third element to.
4005
    A4: the value to set the fourth element to.
4006

4007
  @bold(Note): it is more efficient to use TIVector4.Init instead. }
4008
function IVector4(const A1, A2, A3, A4: Integer): TIVector4; overload;
4009

4010
{******************************************************}
4011
{* Angle and Trigonometry Functions                   *}
4012
{******************************************************}
4013

4014
{ Converts degrees to radians.
4015

4016
  Parameters:
4017
    ADegrees: number of degrees.
4018

4019
  Returns:
4020
    ADegrees converted to radians. }
4021
function Radians(const ADegrees: Single): Single; overload; inline;
4022
function Radians(const ADegrees: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4023
function Radians(const ADegrees: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4024
function Radians(const ADegrees: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4025

4026
{ Converts radians to degrees.
4027

4028
  Parameters:
4029
    ARadians: number of radians.
4030

4031
  Returns:
4032
    ARadians converted to degrees. }
4033
function Degrees(const ARadians: Single): Single; overload; inline;
4034
function Degrees(const ARadians: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4035
function Degrees(const ARadians: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4036
function Degrees(const ARadians: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4037

4038
{ Calculates the sine of an angle.
4039

4040
  Parameters:
4041
    ARadians: the angle in radians.
4042

4043
  Returns:
4044
    The sine of the given angle.
4045

4046
  @bold(Note): You probably want to use FastSin instead, which is much faster
4047
  but still very accurate to about +/-4000 radians (or +/-230,000 degrees). }
4048
function Sin(const ARadians: Single): Single; overload; inline;
4049
function Sin(const ARadians: TVector2): TVector2; overload; inline;
4050
function Sin(const ARadians: TVector3): TVector3; overload; inline;
4051
function Sin(const ARadians: TVector4): TVector4; overload; inline;
4052

4053
{ Calculates the cosine of an angle.
4054

4055
  Parameters:
4056
    ARadians: the angle in radians.
4057

4058
  Returns:
4059
    The cosine of the given angle.
4060

4061
  @bold(Note): You probably want to use FastCos instead, which is much faster
4062
  but still very accurate to about +/-4000 radians (or +/-230,000 degrees). }
4063
function Cos(const ARadians: Single): Single; overload; inline;
4064
function Cos(const ARadians: TVector2): TVector2; overload; inline;
4065
function Cos(const ARadians: TVector3): TVector3; overload; inline;
4066
function Cos(const ARadians: TVector4): TVector4; overload; inline;
4067

4068
{ Calculates the sine and cosine of an angle. This is faster than calling Sin
4069
  and Cos separately.
4070

4071
  Parameters:
4072
    ARadians: the angle in radians.
4073
    ASin: is set to the sine of the angle.
4074
    ACos: is set to the cosine of the angle.
4075

4076
  @bold(Note): You probably want to use FastSinCos instead, which is much faster
4077
  but still very accurate to about +/-4000 radians (or +/-230,000 degrees). }
4078
procedure SinCos(const ARadians: Single; out ASin, ACos: Single); overload;
4079
procedure SinCos(const ARadians: TVector2; out ASin, ACos: TVector2); overload;
4080
procedure SinCos(const ARadians: TVector3; out ASin, ACos: TVector3); overload;
4081
procedure SinCos(const ARadians: TVector4; out ASin, ACos: TVector4); overload;
4082

4083
{ Calculates the tangent of an angle.
4084

4085
  Parameters:
4086
    ARadians: the angle in radians.
4087

4088
  Returns:
4089
    The tangent of the given angle.
4090

4091
  @bold(Note): You probably want to use FastTan instead, which is much faster
4092
  but still very accurate to about +/-4000 radians (or +/-230,000 degrees). }
4093
function Tan(const ARadians: Single): Single; overload; inline;
4094
function Tan(const ARadians: TVector2): TVector2; overload; inline;
4095
function Tan(const ARadians: TVector3): TVector3; overload; inline;
4096
function Tan(const ARadians: TVector4): TVector4; overload; inline;
4097

4098
{ Calculates the angle whose sine is A.
4099

4100
  Parameters:
4101
    A: the sine whose angle to calculate. Results are undefined if (A < -1) or
4102
      (A > 1).
4103

4104
  Returns:
4105
    The angle in radians, in the range [-Pi/2..Pi/2] }
4106
function ArcSin(const A: Single): Single; overload; inline;
4107
function ArcSin(const A: TVector2): TVector2; overload; inline;
4108
function ArcSin(const A: TVector3): TVector3; overload; inline;
4109
function ArcSin(const A: TVector4): TVector4; overload; inline;
4110

4111
{ Calculates the angle whose cosine is A.
4112

4113
  Parameters:
4114
    A: the cosine whose angle to calculate. Results are undefined if (A < -1) or
4115
      (A > 1).
4116

4117
  Returns:
4118
    The angle in radians, in the range [0..Pi] }
4119
function ArcCos(const A: Single): Single; overload; inline;
4120
function ArcCos(const A: TVector2): TVector2; overload; inline;
4121
function ArcCos(const A: TVector3): TVector3; overload; inline;
4122
function ArcCos(const A: TVector4): TVector4; overload; inline;
4123

4124
{ Calculates the angle whose tangent is A.
4125

4126
  Parameters:
4127
    A: the tangent whose angle to calculate.
4128

4129
  Returns:
4130
    The angle in radians, in the range [-Pi/2..Pi/2] }
4131
function ArcTan(const A: Single): Single; overload; inline;
4132
function ArcTan(const A: TVector2): TVector2; overload; inline;
4133
function ArcTan(const A: TVector3): TVector3; overload; inline;
4134
function ArcTan(const A: TVector4): TVector4; overload; inline;
4135

4136
{ Calculates the principal value of the arctangent of Y/X, expressed in radians.
4137

4138
  Parameters:
4139
    Y: proportion of the Y-coordinate.
4140
    X: proportion of the X-coordinate.
4141

4142
  Returns:
4143
    The angle in radians, in the range [-Pi..Pi] }
4144
function ArcTan2(const Y, X: Single): Single; overload; inline;
4145
function ArcTan2(const Y, X: TVector2): TVector2; overload; inline;
4146
function ArcTan2(const Y, X: TVector3): TVector3; overload; inline;
4147
function ArcTan2(const Y, X: TVector4): TVector4; overload; inline;
4148

4149
{ Calculates a hyperbolic sine.
4150

4151
  Parameters:
4152
    A: the value.
4153

4154
  Returns:
4155
    The hyperbolic sine of A. }
4156
function Sinh(const A: Single): Single; overload; inline;
4157
function Sinh(const A: TVector2): TVector2; overload; inline;
4158
function Sinh(const A: TVector3): TVector3; overload; inline;
4159
function Sinh(const A: TVector4): TVector4; overload; inline;
4160

4161
{ Calculates a hyperbolic cosine.
4162

4163
  Parameters:
4164
    A: the value.
4165

4166
  Returns:
4167
    The hyperbolic cosine of A. }
4168
function Cosh(const A: Single): Single; overload; inline;
4169
function Cosh(const A: TVector2): TVector2; overload; inline;
4170
function Cosh(const A: TVector3): TVector3; overload; inline;
4171
function Cosh(const A: TVector4): TVector4; overload; inline;
4172

4173
{ Calculates a hyperbolic tangent.
4174

4175
  Parameters:
4176
    A: the value.
4177

4178
  Returns:
4179
    The hyperbolic tangent of A. }
4180
function Tanh(const A: Single): Single; overload; inline;
4181
function Tanh(const A: TVector2): TVector2; overload; inline;
4182
function Tanh(const A: TVector3): TVector3; overload; inline;
4183
function Tanh(const A: TVector4): TVector4; overload; inline;
4184

4185
{ Calculates an inverse hyperbolic sine.
4186

4187
  Parameters:
4188
    A: the value.
4189

4190
  Returns:
4191
    The inverse hyperbolic sine of A. }
4192
function ArcSinh(const A: Single): Single; overload; inline;
4193
function ArcSinh(const A: TVector2): TVector2; overload; inline;
4194
function ArcSinh(const A: TVector3): TVector3; overload; inline;
4195
function ArcSinh(const A: TVector4): TVector4; overload; inline;
4196

4197
{ Calculates an inverse hyperbolic cosine.
4198

4199
  Parameters:
4200
    A: the value.
4201

4202
  Returns:
4203
    The inverse hyperbolic cosine of A. }
4204
function ArcCosh(const A: Single): Single; overload; inline;
4205
function ArcCosh(const A: TVector2): TVector2; overload; inline;
4206
function ArcCosh(const A: TVector3): TVector3; overload; inline;
4207
function ArcCosh(const A: TVector4): TVector4; overload; inline;
4208

4209
{ Calculates an inverse hyperbolic tangent.
4210

4211
  Parameters:
4212
    A: the value.
4213

4214
  Returns:
4215
    The inverse hyperbolic tangent of A. }
4216
function ArcTanh(const A: Single): Single; overload; inline;
4217
function ArcTanh(const A: TVector2): TVector2; overload; inline;
4218
function ArcTanh(const A: TVector3): TVector3; overload; inline;
4219
function ArcTanh(const A: TVector4): TVector4; overload; inline;
4220

4221
{******************************************************}
4222
{* Exponential Functions                              *}
4223
{******************************************************}
4224

4225
{ Calculates ABase raised to the AExponent power.
4226

4227
  Parameters:
4228
    ABase: the base value. Must be >= 0.
4229
    AExponent: the exponent value.
4230

4231
  Returns:
4232
    ABase raised to the AExponent power. Results are undefined if both ABase=0
4233
    and AExponent<=0.
4234

4235
  @bold(Note): Consider using FastPower instead, which is much faster, but at a
4236
  maximum relative error of about 0.2%. }
4237
function Power(const ABase, AExponent: Single): Single; overload; inline;
4238
function Power(const ABase, AExponent: TVector2): TVector2; overload; inline;
4239
function Power(const ABase, AExponent: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4240
function Power(const ABase, AExponent: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4241

4242
{ Calculates a natural exponentiation (that is, e raised to a given power).
4243

4244
  Parameters:
4245
    A: the value
4246

4247
  Returns:
4248
    The natural exponentation of A (e raised to the power of A).
4249

4250
  @bold(Note): Consider using FastExp instead, which is much faster, but at a
4251
  maximum absolute error of about 0.00001. }
4252
function Exp(const A: Single): Single; overload; inline;
4253
function Exp(const A: TVector2): TVector2; overload; inline;
4254
function Exp(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4255
function Exp(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4256

4257
{ Calculates a natural logarithm.
4258

4259
  Parameters:
4260
    A: the value. Results are undefined if A <= 0.
4261

4262
  Returns:
4263
    The natural logarithm of A (that is, the value B so that A equals e raised
4264
    to the power of B)
4265

4266
  @bold(Note): Consider using FastLn instead, which is much faster, but at a
4267
  maximum absolute error of about 0.00003. }
4268
function Ln(const A: Single): Single; overload; inline;
4269
function Ln(const A: TVector2): TVector2; overload; inline;
4270
function Ln(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4271
function Ln(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4272

4273
{ Calculates 2 raised to a power.
4274

4275
  Parameters:
4276
    A: the value
4277

4278
  Returns:
4279
    2 raised to the power of A.
4280

4281
  @bold(Note): Consider using FastExp2 instead, which is much faster, but less
4282
  accurate. }
4283
function Exp2(const A: Single): Single; overload; inline;
4284
function Exp2(const A: TVector2): TVector2; overload; inline;
4285
function Exp2(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4286
function Exp2(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4287

4288
{ Calculates a base 2 logarithm.
4289

4290
  Parameters:
4291
    A: the value. Results are undefined if A <= 0.
4292

4293
  Returns:
4294
    The base 2 logarithm of A (that is, the value B so that A equals 2 raised
4295
    to the power of B)
4296

4297
  @bold(Note): Consider using FastLog2 instead, which is much faster, but at a
4298
  maximum absolute error of about 0.0002. }
4299
function Log2(const A: Single): Single; overload; inline;
4300
function Log2(const A: TVector2): TVector2; overload; inline;
4301
function Log2(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4302
function Log2(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4303

4304
{ Calculates a square root.
4305

4306
  Parameters:
4307
    A: the value. Results are undefined if A < 0.
4308

4309
  Returns:
4310
    The square root of A.
4311

4312
  @bold(Note): If you plan to divide a certain value by the returned square
4313
  root, then consider using InverseSqrt instead. That version is usually faster
4314
  to calculate and you can replace an expensive division with a faster
4315
  multiplication.  }
4316
function Sqrt(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4317
function Sqrt(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4318
function Sqrt(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4319
function Sqrt(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4320

4321
{ Calculates an inverse square root.
4322

4323
  Parameters:
4324
    A: the value. Results are undefined if A <= 0.
4325

4326
  Returns:
4327
    1/Sqrt(A)
4328

4329
  @bold(Note): You can use this function if you need to divide a given value by
4330
  a square root. The inverse square root is usually faster to calculate, and you
4331
  can replace an expensive division with a faster multiplication.
4332

4333
  @bold(Note): The SIMD optimized versions of these functions use an
4334
  approximation, resulting in a very small error. }
4335
function InverseSqrt(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4336
function InverseSqrt(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4337
function InverseSqrt(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4338
function InverseSqrt(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4339

4340
{******************************************************}
4341
{* Fast Approximate Functions                         *}
4342
{******************************************************}
4343

4344
{ These functions are usually (much) faster than their counterparts, but are
4345
  less accurate. For gaming and animation, this loss in accuracy is perfectly
4346
  acceptible and outweighed by the increase in speed.
4347

4348
  These functions use approximations as described in:
4349
    http://gallium.inria.fr/blog/fast-vectorizable-math-approx/
4350
    http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html
4351
    http://gruntthepeon.free.fr/ssemath/ }
4352

4353
{ Calculates the sine of an angle.
4354

4355
  Parameters:
4356
    ARadians: the angle in radians.
4357

4358
  Returns:
4359
    The (approximate) sine of the given angle.
4360

4361
  @bold(Note): This function provides excellent precisions when ARadians is
4362
  about the range [-4000..4000] (about +/-230,000 degrees) }
4363
function FastSin(const ARadians: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4364
function FastSin(const ARadians: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4365
function FastSin(const ARadians: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4366
function FastSin(const ARadians: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4367

4368
{ Calculates the cosine of an angle.
4369

4370
  Parameters:
4371
    ARadians: the angle in radians.
4372

4373
  Returns:
4374
    The (approximate) cosine of the given angle.
4375

4376
  @bold(Note): This function provides excellent precisions when ARadians is
4377
  about the range [-4000..4000] (about +/-230,000 degrees) }
4378
function FastCos(const ARadians: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4379
function FastCos(const ARadians: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4380
function FastCos(const ARadians: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4381
function FastCos(const ARadians: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4382

4383
{ Calculates the sine and cosine of an angle. This is faster than calling
4384
  FastSin and FastCos separately.
4385

4386
  Parameters:
4387
    ARadians: the angle in radians.
4388
    ASin: is set to the (approximate) sine of the angle.
4389
    ACos: is set to the (approximate) cosine of the angle.
4390

4391
  @bold(Note): This function provides excellent precisions when ARadians is
4392
  about the range [-4000..4000] (about +/-230,000 degrees) }
4393
procedure FastSinCos(const ARadians: Single; out ASin, ACos: Single); overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4394
procedure FastSinCos(const ARadians: TVector2; out ASin, ACos: TVector2); overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4395
procedure FastSinCos(const ARadians: TVector3; out ASin, ACos: TVector3); overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4396
procedure FastSinCos(const ARadians: TVector4; out ASin, ACos: TVector4); overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4397

4398
{ Calculates the tangent of an angle.
4399

4400
  Parameters:
4401
    ARadians: the angle in radians.
4402

4403
  Returns:
4404
    The (approximate) tangent of the given angle.
4405

4406
  @bold(Note): This function provides excellent precisions when ARadians is
4407
  about the range [-4000..4000] (about +/-230,000 degrees) }
4408
function FastTan(const ARadians: Single): Single; overload;
4409
function FastTan(const ARadians: TVector2): TVector2; overload;
4410
function FastTan(const ARadians: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4411
function FastTan(const ARadians: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4412

4413
{ Calculates the principal value of the arctangent of Y/X, expressed in radians.
4414

4415
  Parameters:
4416
    Y: proportion of the Y-coordinate.
4417
    X: proportion of the X-coordinate.
4418

4419
  Returns:
4420
    The (approximate) angle in radians, in the range [-Pi..Pi] }
4421
function FastArcTan2(const Y, X: Single): Single; overload;
4422
function FastArcTan2(const Y, X: TVector2): TVector2; overload;
4423
function FastArcTan2(const Y, X: TVector3): TVector3; overload;
4424
function FastArcTan2(const Y, X: TVector4): TVector4; overload;
4425

4426
{ Calculates ABase raised to the AExponent power.
4427

4428
  Parameters:
4429
    ABase: the base value. Must be >= 0.
4430
    AExponent: the exponent value.
4431

4432
  Returns:
4433
    (Approximate) ABase raised to the AExponent power. Results are undefined if
4434
    both ABase=0 and AExponent<=0.
4435

4436
  @bold(Note): The error depends on the magnitude of the result. The relative
4437
  error is at most about 0.2% }
4438
function FastPower(const ABase, AExponent: Single): Single; overload; inline;
4439
function FastPower(const ABase, AExponent: TVector2): TVector2; overload; inline;
4440
function FastPower(const ABase, AExponent: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4441
function FastPower(const ABase, AExponent: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4442

4443
{ Calculates a natural exponentiation (that is, e raised to a given power).
4444

4445
  Parameters:
4446
    A: the value
4447

4448
  Returns:
4449
    The (approximate) natural exponentation of A (e raised to the power of A)
4450

4451
  @bold(Note): Maximum absolute error is about 0.00001 }
4452
function FastExp(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4453
function FastExp(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4454
function FastExp(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4455
function FastExp(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4456

4457
{ Calculates a natural logarithm.
4458

4459
  Parameters:
4460
    A: the value. Results are undefined if A <= 0.
4461

4462
  Returns:
4463
    The (approximate) natural logarithm of A (that is, the value B so that A
4464
    equals e raised to the power of B)
4465

4466
  @bold(Note): Maximum absolute error is about 0.00003. }
4467
function FastLn(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4468
function FastLn(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4469
function FastLn(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4470
function FastLn(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4471

4472
{ Calculates a base 2 logarithm.
4473

4474
  Parameters:
4475
    A: the value. Results are undefined if A <= 0.
4476

4477
  Returns:
4478
    The (approximate) base 2 logarithm of A (that is, the value B so that A
4479
    equals 2 raised to the power of B)
4480

4481
  @bold(Note): Maximum absolute error is about 0.0002 }
4482
function FastLog2(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4483
function FastLog2(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4484
function FastLog2(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4485
function FastLog2(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4486

4487
{ Calculates 2 raised to a power.
4488

4489
  Parameters:
4490
    A: the value. Must be in the range [-127..127] for valid results.
4491

4492
  Returns:
4493
    (Approximate) 2 raised to the power of A.
4494

4495
  @bold(Note): If A needs to be outside of the range [-127..127], then use Exp2
4496
  instead. }
4497
function FastExp2(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4498
function FastExp2(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4499
function FastExp2(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4500
function FastExp2(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4501

4502
{******************************************************}
4503
{* Common Functions                                   *}
4504
{******************************************************}
4505

4506
{ Calculates an absolute value.
4507

4508
  Parameters:
4509
    A: the value.
4510

4511
  Returns:
4512
    A if A >= 0, otherwise -A. }
4513
function Abs(const A: Single): Single; overload; inline;
4514
function Abs(const A: TVector2): TVector2; overload; inline;
4515
function Abs(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4516
function Abs(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4517

4518
{ Calculates the sign of a value.
4519

4520
  Parameters:
4521
    A: the value.
4522

4523
  Returns:
4524
    -1.0 if A < 0, 0.0 if A = 0, or 1.0 if A > 0. }
4525
function Sign(const A: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4526
function Sign(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4527
function Sign(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4528
function Sign(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4529

4530
{ Rounds a value towards negative infinity.
4531

4532
  Parameters:
4533
    A: the value.
4534

4535
  Returns:
4536
    A value equal to the nearest integer that is less than or equal to A. }
4537
function Floor(const A: Single): Integer; overload; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
4538
function Floor(const A: TVector2): TIVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4539
function Floor(const A: TVector3): TIVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4540
function Floor(const A: TVector4): TIVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4541

4542
{ Rounds a value towards 0.
4543

4544
  Parameters:
4545
    A: the value.
4546

4547
  Returns:
4548
    The value A rounded towards 0. That is, with its fractional part removed. }
4549
function Trunc(const A: Single): Integer; overload; inline;
4550
function Trunc(const A: TVector2): TIVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4551
function Trunc(const A: TVector3): TIVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4552
function Trunc(const A: TVector4): TIVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4553

4554
{ Rounds a value towards its nearest integer.
4555

4556
  Parameters:
4557
    A: the value.
4558

4559
  Returns:
4560
    The integer value closest to A. If A is exactly between two integer values
4561
    (if the fraction is 0.5), then the result is the even number. }
4562
function Round(const A: Single): Integer; overload; inline;
4563
function Round(const A: TVector2): TIVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4564
function Round(const A: TVector3): TIVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4565
function Round(const A: TVector4): TIVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4566

4567
{ Rounds a value towards positive infinity.
4568

4569
  Parameters:
4570
    A: the value.
4571

4572
  Returns:
4573
    A value equal to the nearest integer that is greater than or equal to A. }
4574
function Ceil(const A: Single): Integer; overload; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
4575
function Ceil(const A: TVector2): TIVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4576
function Ceil(const A: TVector3): TIVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4577
function Ceil(const A: TVector4): TIVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4578

4579
{ Returns the fractional part of a number.
4580

4581
  Parameters:
4582
    A: the value.
4583

4584
  Returns:
4585
    The fractional part of A, calculated as to A - Trunc(A) }
4586
function Frac(const A: Single): Single; overload; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
4587
function Frac(const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4588
function Frac(const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4589
function Frac(const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4590

4591
{ Modulus. Calculates the remainder of a floating-point division.
4592

4593
  Parameters:
4594
    A: the dividend.
4595
    B: the divisor.
4596

4597
  Returns:
4598
    The remainder of A / B, calculated as A - B * Trunc(A / B)
4599

4600
  @bold(Note): When used with vectors, B can be a scalar or a vector. }
4601
function FMod(const A, B: Single): Single; overload; inline;
4602
function FMod(const A: TVector2; const B: Single): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4603
function FMod(const A, B: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4604
function FMod(const A: TVector3; const B: Single): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4605
function FMod(const A, B: TVector3): TVector3; overload; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
4606
function FMod(const A: TVector4; const B: Single): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4607
function FMod(const A, B: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4608

4609
{ Splits a floating-point value into its integer and fractional parts.
4610

4611
  Parameters:
4612
    A: the value to split.
4613
    B: is set to the integer part of A
4614

4615
  Returns:
4616
    The fractional part of A.
4617

4618
  @bold(Note): Both the return value and output parameter B will have the same
4619
  sign as A. }
4620
function ModF(const A: Single; out B: Integer): Single; overload; {$IF Defined(FM_INLINE) or Defined(CPUX64)}inline;{$ENDIF}
4621
function ModF(const A: TVector2; out B: TIVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4622
function ModF(const A: TVector3; out B: TIVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4623
function ModF(const A: TVector4; out B: TIVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4624

4625
{ Calculates the minimum of two values.
4626

4627
  Parameters:
4628
    A: the first value.
4629
    B: the second value.
4630

4631
  Returns:
4632
    The minimum of A and B.
4633

4634
  @bold(Note): When used with vectors, B can be a scalar or a vector. }
4635
function Min(const A, B: Single): Single; overload; inline;
4636
function Min(const A: TVector2; const B: Single): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4637
function Min(const A, B: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4638
function Min(const A: TVector3; const B: Single): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4639
function Min(const A, B: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4640
function Min(const A: TVector4; const B: Single): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4641
function Min(const A, B: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4642

4643
{ Calculates the maximum of two values.
4644

4645
  Parameters:
4646
    A: the first value.
4647
    B: the second value.
4648

4649
  Returns:
4650
    The maximum of A and B.
4651

4652
  @bold(Note): When used with vectors, B can be a scalar or a vector. }
4653
function Max(const A, B: Single): Single; overload; inline;
4654
function Max(const A: TVector2; const B: Single): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4655
function Max(const A, B: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4656
function Max(const A: TVector3; const B: Single): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4657
function Max(const A, B: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4658
function Max(const A: TVector4; const B: Single): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4659
function Max(const A, B: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4660

4661
{ Clamps a given value into a range.
4662

4663
  Parameters:
4664
    A: the value to clamp.
4665
    AMin: the minimum value of the range.
4666
    AMax: the maximum value of the range. Must be >= AMin.
4667

4668
  Returns:
4669
    A clamped to the range [AMin..AMax]. Results are undefined if AMin > AMax.
4670
    No error checking is performed for this situation.
4671

4672
  @bold(Note): When used with vectors, AMin and AMax can be scalars or vectors. }
4673
function EnsureRange(const A, AMin, AMax: Single): Single; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4674
function EnsureRange(const A: TVector2; const AMin, AMax: Single): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4675
function EnsureRange(const A, AMin, AMax: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4676
function EnsureRange(const A: TVector3; const AMin, AMax: Single): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4677
function EnsureRange(const A, AMin, AMax: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4678
function EnsureRange(const A: TVector4; const AMin, AMax: Single): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4679
function EnsureRange(const A, AMin, AMax: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4680

4681
{ Calculates a linear blend between two values, using on a progress value.
4682

4683
  Parameters:
4684
    A: the first value.
4685
    B: the second value.
4686
    T: the progress value, usually between 0.0 and 1.0.
4687

4688
  Returns:
4689
    A value interpolated between A and B, as controlled by T. If T=0, then A
4690
    is returned. If T=1 then B is returned. For values in between 0 and 1, the
4691
    result is linearly interpolated with the formula "A * (1 - T) + (B * T)".
4692

4693
  @bold(Note): When used with vectors, T can be a scalar or a vector. }
4694
function Mix(const A, B, T: Single): Single; overload; inline;
4695
function Mix(const A, B: TVector2; const T: Single): TVector2; overload; inline;
4696
function Mix(const A, B, T: TVector2): TVector2; overload; inline;
4697
function Mix(const A, B: TVector3; const T: Single): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4698
function Mix(const A, B, T: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4699
function Mix(const A, B: TVector4; const T: Single): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4700
function Mix(const A, B, T: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4701

4702
{ Step function.
4703

4704
  Parameters:
4705
    AEdge: the edge value.
4706
    A: the value to check.
4707

4708
  Returns:
4709
    0.0 if A < AEdge. Otherwise it returns 1.0.
4710

4711
  @bold(Note): When used with vectors, AEdge can be a scalar or a vector. }
4712
function Step(const AEdge, A: Single): Single; overload; inline;
4713
function Step(const AEdge: Single; const A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4714
function Step(const AEdge, A: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4715
function Step(const AEdge: Single; const A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4716
function Step(const AEdge, A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4717
function Step(const AEdge: Single; const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4718
function Step(const AEdge, A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4719

4720
{ Performs smooth Hermite interpolation between 0 and 1.
4721

4722
  Parameters:
4723
    AEdge0: the left value of the edge.
4724
    AEdge1: the right value of the edge.
4725
    A: the value used to control the interpolation.
4726

4727
  Returns:
4728
    0.0 if A <= AEdge0 and 1.0 if A >= AEdge1. Otherwise it performs a smooth
4729
    Hermite interpolation between 0 and 1, based on the position of A between
4730
    AEdge0 and AEdge1. This is useful in cases where you would want a threshold
4731
    function with a smooth transition (as compared to the Step function). The
4732
    graph would show a curve increasing slowly from 0.0, the speeding up towards
4733
    0.5 and finally slowing down towards 1.0.
4734

4735
  @bold(Note): The interpolation is calculated using the algorithm:
4736

4737
      <source>
4738
      T := EnsureRange((A - AEdge0) / (AEdge1 - AEdge0), 0, 1);
4739
      Result := T * T * (3 - 2 * T);
4740
      </source>
4741

4742
    Results are undefined if AEdge0 >= AEdge1. When used with vectors, AEdge0
4743
    and AEdge1 can be scalars or vectors. }
4744
function SmoothStep(const AEdge0, AEdge1, A: Single): Single; overload; inline;
4745
function SmoothStep(const AEdge0, AEdge1: Single; const A: TVector2): TVector2; overload; inline;
4746
function SmoothStep(const AEdge0, AEdge1, A: TVector2): TVector2; overload; inline;
4747
function SmoothStep(const AEdge0, AEdge1: Single; const A: TVector3): TVector3; overload; inline;
4748
function SmoothStep(const AEdge0, AEdge1, A: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4749
function SmoothStep(const AEdge0, AEdge1: Single; const A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4750
function SmoothStep(const AEdge0, AEdge1, A: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4751

4752
{ Fused Multiply and Add (if available).
4753

4754
  Parameters:
4755
    A: the first value.
4756
    B: the second value.
4757
    C: the third value.
4758

4759
  Returns:
4760
    (A * B) + C
4761

4762
  @bold(Note): On ARM platforms (iOS and Android), the calculation is performed
4763
  with as a single (fused) operation. This provides better precision (because it
4764
  skips the intermediate rounding).
4765

4766
  On other platforms, this is not really a fused operation, but just a separate
4767
  muliplication and addition. }
4768
function FMA(const A, B, C: Single): Single; overload; inline;
4769
function FMA(const A, B, C: TVector2): TVector2; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4770
function FMA(const A, B, C: TVector3): TVector3; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4771
function FMA(const A, B, C: TVector4): TVector4; overload; {$IFDEF FM_INLINE}inline;{$ENDIF}
4772

4773
{******************************************************}
4774
{* Matrix Functions                                   *}
4775
{******************************************************}
4776

4777
{ Treats the first parameter C as a column vector (matrix with one column) and
4778
  the second parameter R as a row vector (matrix with one row) and does a linear
4779
  algebraic matrix multiply C * R, yielding a matrix whose number of rows and
4780
  columns matches that of the two vectors.
4781

4782
  Parameters:
4783
    C: the column vector.
4784
    R: the row vector.
4785

4786
  Returns:
4787
    The outer product of C and R. }
4788
function OuterProduct(const C, R: TVector2): TMatrix2; overload;
4789
function OuterProduct(const C, R: TVector3): TMatrix3; overload;
4790
function OuterProduct(const C, R: TVector4): TMatrix4; overload;
4791

4792
{******************************************************}
4793
{* Configuration Functions                            *}
4794
{******************************************************}
4795

4796
{ Disables floating-point exceptions. Instead invalid floating-point operations
4797
  will return one of the following values:
4798
  * 0: if underflow occurs (if the value is smaller than can be represented
4799
      using floating-point). For example by evaluating "0.5 * MinSingle".
4800
  * MaxSingle/MaxDouble: if there is not enough precision available.
4801
      For example by evaluating "MaxSingle + 1".
4802
  * +/-INF: when a division by zero or overflow occurs. For example by
4803
      evaluating "Value / 0" or "MaxSingle * 2".
4804
  * +/-NAN: when an invalid operation occurs. For example by evaluating
4805
      "Sqrt(-1)"
4806

4807
  @bold(Note): On some platforms, this only disables exceptions on the thread
4808
  that calls this routine. So in multi-threaded scenarios, it is best to call
4809
  this routine in the Execute block of every thread where you want to ignore
4810
  floating point exceptions.
4811

4812
  @bold(Note): For more fine-grained control over which exception types to
4813
  disable, use the SetExceptionMask and/or SetSSEExceptionMask functions in the
4814
  System.Math unit.}
4815
procedure DisableFloatingPointExceptions;
4816

4817
{ Restore the floating-point exception flags to the state before you called
4818
  DisableFloatingPointExceptions }
4819
procedure RestoreFloatingPointExceptions;
4820

4821
{$INCLUDE 'Neslib.FastMath.Internal.inc'}
4822

4823
implementation
4824

4825
// Platform-independent implementations
4826
{$INCLUDE 'Neslib.FastMath.Common.inc'}
4827

4828
{$IF Defined(FM_PASCAL)}
4829
  // Pascal implementations
4830
  {$INCLUDE 'Neslib.FastMath.Pascal.inc'}
4831
{$ELSEIF Defined(FM_X86)}
4832
  // 32-bit SSE2 implementations
4833
  {$INCLUDE 'Neslib.FastMath.Sse2_32.inc'}
4834
{$ELSEIF Defined(FM_X64)}
4835
  // 64-bit SSE2 implementations
4836
  {$IF Defined(MACOS64)}
4837
    {$INCLUDE 'Neslib.FastMath.Sse2_64.MacOS.inc'}
4838
  {$ELSE}
4839
    {$INCLUDE 'Neslib.FastMath.Sse2_64.inc'}
4840
  {$ENDIF}
4841
{$ELSEIF Defined(FM_ARM)}
4842
  // Arm NEON/Arm64 implementations
4843
  {$INCLUDE 'Neslib.FastMath.Arm.inc'}
4844
{$ENDIF}
4845

4846
end.
4847

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.