Table of Contents

include/AK/Tools/Common/AkVectors.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
00003 released in source code form as part of the SDK installer package.
00004 
00005 Commercial License Usage
00006 
00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
00008 may use this file in accordance with the end user license agreement provided 
00009 with the software or, alternatively, in accordance with the terms contained in a
00010 written agreement between you and Audiokinetic Inc.
00011 
00012 Apache License Usage
00013 
00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the 
00015 "Apache License"); you may not use this file except in compliance with the 
00016 Apache License. You may obtain a copy of the Apache License at 
00017 http://www.apache.org/licenses/LICENSE-2.0.
00018 
00019 Unless required by applicable law or agreed to in writing, software distributed
00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
00022 the specific language governing permissions and limitations under the License.
00023 
00024   Version: <VERSION>  Build: <BUILDNUMBER>
00025   Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc.
00026 *******************************************************************************/
00027 
00028 // AkVectors.h
00029 //
00030 
00031 #pragma once
00032 
00033 #include <AK/SoundEngine/Common/AkTypes.h>
00034 #include <AK/SoundEngine/Common/AkSimd.h>
00035 #include <AK/SoundEngine/Common/AkSpeakerVolumes.h>
00036 #include <AK/SoundEngine/Common/IAkPluginMemAlloc.h>
00037 #include <AK/Tools/Common/AkArray.h>
00038 #include <AK/Tools/Common/AkObject.h>
00039 
00040 #include <math.h>
00041 #include <stdio.h>
00042 #include <float.h>
00043 
00044 //#define AKVBAP_DEBUG 1
00045 //#define AKPORTALS_DEBUG
00046 
00047 #define AKVECTORS_PI                (3.1415926535897932384626433832795f)
00048 #define AKVECTORS_TWOPI             (6.283185307179586476925286766559f)
00049 #define AKVECTORS_PIOVERTWO         (1.5707963267948966192313216916398f)
00050 #define AKVECTORS_EPSILON           (1.0e-38f)                                  // epsilon value for fast log(0)
00051 
00052 class Ak4DVector
00053 {
00054 public:
00055     //-----------------------------------------------------------
00056     // Constructor/Destructor functions
00057     Ak4DVector()
00058     {
00059         v[0] = 0.0f;
00060         v[1] = 0.0f;
00061         v[2] = 0.0f;
00062         v[3] = 0.0f;
00063     }
00064 
00065     Ak4DVector(const AkVector& b)
00066     {
00067         v[0] = b.X;
00068         v[1] = b.Y;
00069         v[2] = b.Z;
00070         v[3] = 1;
00071     }
00072 
00073     ~Ak4DVector(){}
00074 
00075     //-----------------------------------------------------------
00076     // Basic vector operators
00077     Ak4DVector operator=(const Ak4DVector& b)
00078     {
00079         v[0] = b.v[0];
00080         v[1] = b.v[1];
00081         v[2] = b.v[2];
00082         v[3] = b.v[3];
00083 
00084         return *this;
00085     }
00086 
00087     Ak4DVector operator/=(const AkReal32 f)
00088     {
00089         v[0] = v[0] / f;
00090         v[1] = v[1] / f;
00091         v[2] = v[2] / f;
00092         v[3] = v[3] / f;
00093 
00094         return *this;
00095     }
00096 
00097     Ak4DVector operator-(const Ak4DVector& b) const
00098     {
00099         Ak4DVector p;
00100 
00101         p.v[0] = v[0] - b.v[0];
00102         p.v[1] = v[1] - b.v[1];
00103         p.v[2] = v[2] - b.v[2];
00104         p.v[3] = v[3] - b.v[3];
00105 
00106         return p;
00107     }
00108 
00109     AkReal32    v[4];
00110 };
00111 
00112 struct Ak3DIntVector
00113 {
00114 public:
00115     Ak3DIntVector(){}
00116     Ak3DIntVector(AkInt32 x, AkInt32 y, AkInt32 z)
00117     {
00118         X = x;
00119         Y = y;
00120         Z = z;
00121     }
00122 
00123     ~Ak3DIntVector(){}
00124 
00125     AkInt32     X;  ///< X Position
00126     AkInt32     Y;  ///< Y Position
00127     AkInt32     Z;  ///< Z Position
00128 };
00129 
00130 class Ak3DVector
00131 {
00132 public:
00133     //-----------------------------------------------------------
00134     // Constructor/Destructor functions
00135     Ak3DVector() :
00136         X(0.f),
00137         Y(0.f),
00138         Z(0.f)
00139     {}
00140 
00141     Ak3DVector(
00142         AkReal32                    x,
00143         AkReal32                    y,
00144         AkReal32                    z)
00145     {
00146         X = x;
00147         Y = y;
00148         Z = z;
00149     }
00150     Ak3DVector(const AkVector& b)
00151     {
00152         X = b.X;
00153         Y = b.Y;
00154         Z = b.Z;
00155     }
00156     explicit Ak3DVector(const AKSIMD_V4F32& in_v4f32)
00157     {
00158         X = AKSIMD_GETELEMENT_V4F32(in_v4f32, 0);
00159         Y = AKSIMD_GETELEMENT_V4F32(in_v4f32, 1);
00160         Z = AKSIMD_GETELEMENT_V4F32(in_v4f32, 2);
00161     }
00162     AkForceInline AKSIMD_V4F32 PointV4F32() const
00163     {
00164         AKSIMD_V4F32 v4f32;
00165         AKSIMD_GETELEMENT_V4F32(v4f32, 0) = X;
00166         AKSIMD_GETELEMENT_V4F32(v4f32, 1) = Y;
00167         AKSIMD_GETELEMENT_V4F32(v4f32, 2) = Z;
00168         AKSIMD_GETELEMENT_V4F32(v4f32, 3) = 1.f;
00169         return v4f32;
00170     }
00171     AkForceInline AKSIMD_V4F32 VectorV4F32() const
00172     {
00173         AKSIMD_V4F32 v4f32;
00174         AKSIMD_GETELEMENT_V4F32(v4f32, 0) = X;
00175         AKSIMD_GETELEMENT_V4F32(v4f32, 1) = Y;
00176         AKSIMD_GETELEMENT_V4F32(v4f32, 2) = Z;
00177         AKSIMD_GETELEMENT_V4F32(v4f32, 3) = 0.f;
00178         return v4f32;
00179     }
00180     ~Ak3DVector() {}
00181 
00182     void Zero()
00183     {
00184         X = 0.f;
00185         Y = 0.f;
00186         Z = 0.f;
00187     }
00188 
00189 
00190     //-----------------------------------------------------------
00191     // Basic vector operators
00192     AkForceInline bool operator==(const Ak3DVector& b) const
00193     {
00194         return X == b.X && Y == b.Y && Z == b.Z;
00195     }
00196 
00197     AkForceInline bool operator!=(const Ak3DVector& b) const
00198     {
00199         return X != b.X || Y != b.Y || Z != b.Z;
00200     }
00201 
00202     AkForceInline Ak3DVector operator=(const Ak3DVector& b)
00203     {
00204         X = b.X;
00205         Y = b.Y;
00206         Z = b.Z;
00207 
00208         return *this;
00209     }
00210 
00211     AkForceInline Ak3DVector operator=(const AkVector& b)
00212     {
00213         X = b.X;
00214         Y = b.Y;
00215         Z = b.Z;
00216 
00217         return *this;
00218     }
00219 
00220     AkForceInline bool operator<(const Ak3DVector& b) const
00221     {
00222         return X < b.X && Y < b.Y && Z < b.Z;
00223     }
00224 
00225     AkForceInline bool operator<=(const Ak3DVector& b) const
00226     {
00227         return X <= b.X && Y <= b.Y && Z <= b.Z;
00228     }
00229 
00230     AkForceInline bool operator>(const Ak3DVector b) const
00231     {
00232         return X > b.X && Y > b.Y && Z > b.Z;
00233     }
00234 
00235     AkForceInline bool operator>=(const Ak3DVector& b) const
00236     {
00237         return X >= b.X && Y >= b.Y && Z >= b.Z;
00238     }
00239 
00240     AkForceInline Ak3DVector operator*=(const AkReal32 f)
00241     {
00242         X = X * f;
00243         Y = Y * f;
00244         Z = Z * f;
00245 
00246         return *this;
00247     }
00248 
00249     AkForceInline Ak3DVector operator/=(const AkReal32 f)
00250     {
00251         AkReal32 oneoverf = 1.f / f;
00252         X = X * oneoverf;
00253         Y = Y * oneoverf;
00254         Z = Z * oneoverf;
00255 
00256         return *this;
00257     }
00258 
00259     AkForceInline Ak3DVector operator*(const Ak3DVector v2) const
00260     {
00261         Ak3DVector v;
00262 
00263         v.X = X * v2.X;
00264         v.Y = Y * v2.Y;
00265         v.Z = Z * v2.Z;
00266 
00267         return v;
00268     }
00269 
00270     AkForceInline Ak3DVector operator*(const AkReal32 f) const
00271     {
00272         Ak3DVector v;
00273 
00274         v.X = X * f;
00275         v.Y = Y * f;
00276         v.Z = Z * f;
00277 
00278         return v;
00279     }
00280 
00281     AkForceInline Ak3DVector operator/(const AkReal32 f) const
00282     {
00283         Ak3DVector v;
00284         AkReal32 oneoverf = 1.f / f;
00285 
00286         v.X = X * oneoverf;
00287         v.Y = Y * oneoverf;
00288         v.Z = Z * oneoverf;
00289 
00290         return v;
00291     }
00292 
00293     AkForceInline Ak3DVector operator+(const AkReal32 f) const
00294     {
00295         Ak3DVector v;
00296 
00297         v.X = X + f;
00298         v.Y = Y + f;
00299         v.Z = Z + f;
00300 
00301         return v;
00302     }
00303 
00304     AkForceInline Ak3DVector operator-(const AkReal32 f) const
00305     {
00306         Ak3DVector v;
00307 
00308         v.X = X - f;
00309         v.Y = Y - f;
00310         v.Z = Z - f;
00311 
00312         return v;
00313     }
00314 
00315     AkForceInline Ak3DVector operator+(const Ak3DVector& b) const
00316     {
00317         Ak3DVector v;
00318 
00319         v.X = X + b.X;
00320         v.Y = Y + b.Y;
00321         v.Z = Z + b.Z;
00322 
00323         return v;
00324     }
00325 
00326     AkForceInline Ak3DVector operator-(const Ak3DVector& b) const
00327     {
00328         Ak3DVector v;
00329 
00330         v.X = X - b.X;
00331         v.Y = Y - b.Y;
00332         v.Z = Z - b.Z;
00333 
00334         return v;
00335     }
00336 
00337     AkForceInline operator AkVector()
00338     {
00339         AkVector v;
00340         v.X = X; v.Y = Y; v.Z = Z;
00341 
00342         return v;
00343     }
00344 
00345 
00346     AkForceInline static Ak3DVector Min(const Ak3DVector& A, const Ak3DVector& B)
00347     {
00348         Ak3DVector min;
00349 
00350         min.X = AkMin(A.X, B.X);
00351         min.Y = AkMin(A.Y, B.Y);
00352         min.Z = AkMin(A.Z, B.Z);
00353 
00354         return min;
00355     }
00356 
00357     AkForceInline static Ak3DVector Max(const Ak3DVector& A, const Ak3DVector& B)
00358     {
00359         Ak3DVector max;
00360 
00361         max.X = AkMax(A.X, B.X);
00362         max.Y = AkMax(A.Y, B.Y);
00363         max.Z = AkMax(A.Z, B.Z);
00364 
00365         return max;
00366     }
00367 
00368     //-----------------------------------------------------------
00369     // Conversion functions
00370     AkForceInline Ak3DVector Rotate180X_90Y() const
00371     {
00372         Ak3DVector v;
00373 
00374         v.X = -X;
00375         v.Y = Z;
00376         v.Z = -Y;
00377 
00378         return v;
00379     }
00380 
00381     AkForceInline Ak3DVector SphericalToCartesian(
00382         const AkReal32              azimuth,
00383         const AkReal32              elevation)
00384     {
00385         AkReal32 cosElevation = cosf(elevation);
00386         X = cosf(azimuth) * cosElevation;
00387         Y = sinf(azimuth) * cosElevation;
00388         Z = sinf(elevation);
00389 
00390         return *this;
00391     }
00392 
00393     // Determinant of 3 column vectors.
00394     static AkReal32 Determinant(
00395         const Ak3DVector &          a,
00396         const Ak3DVector &          b,
00397         const Ak3DVector &          c)
00398     {
00399         return  (a.X*b.Y*c.Z + a.Y*b.Z*c.X + a.Z*b.X*c.Y) -
00400             (a.Z*b.Y*c.X + a.Y*b.X*c.Z + a.X*b.Z*c.Y);
00401     }
00402 
00403     // Convert a vector to a different base
00404     AkForceInline Ak3DVector LinearCombination(
00405         const Ak3DVector&           A,
00406         const Ak3DVector&           B,
00407         const Ak3DVector&           C) const
00408     {
00409         Ak3DVector v;
00410 
00411         AkReal32 d = Determinant(A, B, C);
00412 
00413         if (d < AKVECTORS_EPSILON && d > -AKVECTORS_EPSILON)
00414         {
00415             v.X = 0.0f; v.Y = 0.0f; v.Z = 0.0f;
00416             return v;
00417         }
00418 
00419         // http://mathworld.wolfram.com/MatrixInverse.html
00420         Ak3DVector invA = Ak3DVector(B.Y*C.Z - B.Z*C.Y, A.Z*C.Y - A.Y*C.Z, A.Y*B.Z - A.Z*B.Y);
00421         Ak3DVector invB = Ak3DVector(B.Z*C.X - B.X*C.Z, A.X*C.Z - A.Z*C.X, A.Z*B.X - A.X*B.Z);
00422         Ak3DVector invC = Ak3DVector(B.X*C.Y - B.Y*C.X, A.Y*C.X - A.X*C.Y, A.X*B.Y - A.Y*B.X);
00423 
00424         AkReal32 oneover_d = 1.f / d;
00425         invA *= oneover_d;
00426         invB *= oneover_d;
00427         invC *= oneover_d;
00428 
00429         // Project coordinates using a vector to matrix multiplication
00430         v.X = X * invA.X + Y * invB.X + Z * invC.X;
00431         v.Y = X * invA.Y + Y * invB.Y + Z * invC.Y;
00432         v.Z = X * invA.Z + Y * invB.Z + Z * invC.Z;
00433 
00434         // v /= v.Length();
00435 
00436         return v;
00437     }
00438 
00439     AkForceInline const Ak3DVector& Normalize()
00440     {
00441         AkReal32 l = Length();
00442         if (l != 0.f)
00443         {
00444             X /= l;
00445             Y /= l;
00446             Z /= l;
00447         }
00448         else
00449         {
00450             X = 0.f;
00451             Y = 0.f;
00452             Z = 0.f;
00453         }
00454         return *this;
00455     }
00456 
00457     AkForceInline AkReal32 L2_Norm() const
00458     {
00459         return sqrtf(X*X + Y*Y + Z*Z);
00460     }
00461 
00462     AkForceInline AkReal32 DotProduct(const Ak3DVector& v2) const
00463     {
00464         return X*v2.X + Y*v2.Y + Z*v2.Z;
00465     }
00466 
00467     AkForceInline AkReal32 Dot(const Ak3DVector& v2) const
00468     {
00469         return DotProduct(v2);
00470     }
00471 
00472     AkForceInline Ak3DVector Cross(const Ak3DVector& v) const
00473     {
00474         Ak3DVector uxv;
00475         const Ak3DVector& u = *this;
00476 
00477         uxv.X = u.Y*v.Z - u.Z*v.Y;
00478         uxv.Y = u.Z*v.X - u.X*v.Z;
00479         uxv.Z = u.X*v.Y - u.Y*v.X;
00480 
00481         return uxv;
00482     }
00483     //
00484     AkForceInline AkReal32 Length() const
00485     {
00486         return sqrtf(X*X + Y*Y + Z*Z);
00487     }
00488 
00489     AkForceInline AkReal32 LengthSquared() const
00490     {
00491         return X*X + Y*Y + Z*Z;
00492     }
00493 
00494     // Usefull in VBAP algorithm, only points that are a positive linear composition matters.
00495     AkForceInline bool IsAllPositive() const
00496     {
00497         const AkReal32 POSITIVE_TEST_EPSILON = 0.00001f;
00498         return X >= -POSITIVE_TEST_EPSILON &&
00499             Y >= -POSITIVE_TEST_EPSILON &&
00500             Z >= -POSITIVE_TEST_EPSILON;
00501     }
00502 
00503     AkForceInline Ak3DVector Abs() const
00504     {
00505         Ak3DVector abs = *this;
00506         abs.X = (AkReal32)fabs(abs.X);
00507         abs.Y = (AkReal32)fabs(abs.Y);
00508         abs.Z = (AkReal32)fabs(abs.Z);
00509         return abs;
00510     }
00511 
00512     AkReal32                        X;
00513     AkReal32                        Y;
00514     AkReal32                        Z;
00515 };
00516 
00517 class Ak2DVector
00518 {
00519 public:
00520     //-----------------------------------------------------------
00521     // Constructor/Destructor functions
00522     Ak2DVector(){}
00523     ~Ak2DVector(){}
00524 
00525     Ak2DVector(
00526         AkReal32                    x,
00527         AkReal32                    y)
00528     {
00529         X = x;
00530         Y = y;
00531     }
00532 
00533     //-----------------------------------------------------------
00534     // Basic vector operators
00535     AkForceInline Ak2DVector operator=(const Ak2DVector& b)
00536     {
00537         X = b.X;
00538         Y = b.Y;
00539 
00540         return *this;
00541     }
00542 
00543     AkForceInline Ak2DVector operator=(const AkSphericalCoord& b)
00544     {
00545         X = b.theta;
00546         Y = b.phi;
00547 
00548         return *this;
00549     }
00550 
00551     Ak2DVector operator-(const Ak2DVector& b) const
00552     {
00553         Ak2DVector v;
00554 
00555         v.X = X - b.X;
00556         v.Y = Y - b.Y;
00557 
00558         return v;
00559     }
00560 
00561     Ak2DVector operator*=(const AkReal32 f)
00562     {
00563         X = X * f;
00564         Y = Y * f;
00565 
00566         return *this;
00567     }
00568 
00569     Ak2DVector operator/=(const AkReal32 f)
00570     {
00571         AkReal32 oneoverf = 1.f / f;
00572         X = X * oneoverf;
00573         Y = Y * oneoverf;
00574 
00575         return *this;
00576     }
00577 
00578     AkForceInline bool operator==(const Ak2DVector& b) const
00579     {
00580         return b.X == X && b.Y == Y;
00581     }
00582 
00583     AkForceInline bool operator!=(const Ak2DVector& b) const
00584     {
00585         return b.X != X && b.Y != Y;
00586     }
00587 
00588     AkForceInline AkReal32 Length() const
00589     {
00590         return sqrtf(X*X+Y*Y);
00591     }
00592 
00593     //-----------------------------------------------------------
00594     // Conversion functions
00595     AkForceInline Ak2DVector CartesianToSpherical( const Ak3DVector& in_Cartesian )
00596     {
00597         // (radial, azimuth, elevation)
00598         AkReal32 r = sqrtf( in_Cartesian.X*in_Cartesian.X + in_Cartesian.Y*in_Cartesian.Y + in_Cartesian.Z*in_Cartesian.Z);
00599         AKASSERT( r != 0);
00600 
00601         X = atan2f(in_Cartesian.Y, in_Cartesian.X);
00602         Y = asinf(in_Cartesian.Z / r);
00603 
00604         NormalizeSpherical();
00605 
00606         return *this;
00607     }
00608 
00609     AkForceInline Ak2DVector LinearCombination(
00610         const Ak2DVector&           A,
00611         const Ak2DVector&           B) const
00612     {
00613         Ak2DVector v;
00614 
00615         // Project coordinates using a vector to matrix multiplication
00616         AkReal32 d = (A.X*B.Y - A.Y*B.X);
00617 
00618         if (d < AKVECTORS_EPSILON && d > -AKVECTORS_EPSILON)
00619         {
00620             v.X = 0.0f; v.Y = 0.0f;
00621             return v;
00622         }
00623 
00624         Ak2DVector invA = Ak2DVector( B.Y, -A.Y );
00625         Ak2DVector invB = Ak2DVector( -B.X, A.X );
00626 
00627         AkReal32 oneover_d = 1.f / d;
00628         invA *= oneover_d;
00629         invB *= oneover_d;
00630 
00631         v.X = X * invA.X + Y * invB.X;
00632         v.Y = X * invA.Y + Y * invB.Y;
00633         // v /= v.Length();
00634 
00635         return v;
00636     }
00637 
00638     AkForceInline Ak2DVector NormalizeSpherical() const
00639     {
00640         /*
00641             Normalise spherical coordinates.
00642                 X (azimuthal)   -> [-PI, PI],       circle lies on xy plan,         0 is on X axix
00643                 Y (elevation)   -> [-PI/2, PI/2],   half circle on Z axis,          0 on XY plan, PI/2 straigt up on Z axis.
00644         */
00645 
00646         Ak2DVector v;
00647 
00648         v.X = X;
00649         v.Y = Y;
00650 
00651         if (X > AKVECTORS_PI)
00652             v.X = X - AKVECTORS_TWOPI;
00653 
00654         if (X < -AKVECTORS_PI)
00655             v.X = X + AKVECTORS_TWOPI;
00656 
00657         if (Y > AKVECTORS_PIOVERTWO)
00658             v.Y = Y - AKVECTORS_PI;
00659 
00660         if (Y < -AKVECTORS_PIOVERTWO)
00661             v.Y = Y + AKVECTORS_PI;
00662 
00663         AKASSERT(X<AKVECTORS_PI);
00664         AKASSERT(Y<AKVECTORS_PIOVERTWO);
00665 
00666         return v;
00667     }
00668 
00669     AkForceInline void NormalizeSpherical()
00670     {
00671         /*
00672             Normalise spherical coordinates.
00673                 X (azimuthal)   -> [-PI, PI],       circle lies on xy plan,     0 is on X axix
00674                 Y (elevation)   -> [-PI/2, PI/2],   half circle on Z axis,      0 on XY plan, PI/2 straigt up on Z axis.
00675         */
00676 
00677         if (X > AKVECTORS_PI)
00678             X = X - AKVECTORS_TWOPI;
00679 
00680         if (X < -AKVECTORS_PI)
00681             X = X + AKVECTORS_TWOPI;
00682 
00683         if (Y > AKVECTORS_PIOVERTWO)
00684             Y = Y - AKVECTORS_PI;
00685 
00686         if (Y < -AKVECTORS_PIOVERTWO)
00687             Y = Y + AKVECTORS_PI;
00688     }
00689 
00690     // Useful in VBAP algorithm, only points that are a positive linear composition matters.
00691     AkForceInline bool IsAllPositive() const
00692     {
00693         const AkReal32 POSITIVE_TEST_EPSILON = 0.00001f; //0.005f;
00694         return X >= -POSITIVE_TEST_EPSILON &&
00695             Y >= -POSITIVE_TEST_EPSILON;
00696     }
00697 
00698     AkReal32                        X;
00699     AkReal32                        Y;
00700 };
00701 
00702 
00703 
00704 class AkMatrix4x4
00705 {
00706     static const int MAX_SIZE = 16;
00707 
00708 public:
00709     //-----------------------------------------------------------
00710     // Constructor/Destructor functions
00711     AkMatrix4x4() {}
00712     ~AkMatrix4x4() {}
00713 
00714     //-----------------------------------------------------------
00715     // Basic vector operators
00716     AkMatrix4x4 operator/=(const AkReal32 f)
00717     {
00718         for (int i = 0; i < MAX_SIZE; i++)
00719             m_Data[i] /= f;
00720 
00721         return *this;
00722     }
00723 
00724     AkMatrix4x4 operator=(AkReal32 * in_Data)
00725     {
00726         for (int i = 0; i < MAX_SIZE; i++)
00727         {
00728             m_Data[i] = in_Data[i];
00729         }
00730 
00731         return *this;
00732     }
00733 
00734     AkReal32 m_Data[MAX_SIZE];
00735 };
00736 
00737 class AkMatrix3x3
00738 {
00739 
00740 public:
00741     //-----------------------------------------------------------
00742     // Constructor/Destructor functions
00743     AkMatrix3x3() {}
00744     ~AkMatrix3x3() {}
00745 
00746     //-----------------------------------------------------------
00747     // Basic vector operators
00748     AkMatrix3x3 operator/=(const AkReal32 f)
00749     {
00750         for (int i = 0; i < 3; i++)
00751         {
00752             for (int j = 0; j < 3; j++)
00753             {
00754                 m_Data[i][j] /= f;
00755             }
00756         }
00757         return *this;
00758     }
00759 
00760     AkForceInline AkReal32& operator()(const AkUInt32 row, const AkUInt32 column)
00761     {
00762         return m_Data[column][row];
00763     }
00764 
00765     AkForceInline const AkReal32& operator()(const AkUInt32 row, const AkUInt32 column) const
00766     {
00767         return m_Data[column][row];
00768     }
00769 
00770     AkForceInline Ak3DVector operator*(const Ak3DVector& in_rhs)
00771     {
00772         Ak3DVector res;
00773         res.X = in_rhs.X * m_Data[0][0] + in_rhs.Y * m_Data[1][0] + in_rhs.Z * m_Data[2][0];
00774         res.Y = in_rhs.X * m_Data[0][1] + in_rhs.Y * m_Data[1][1] + in_rhs.Z * m_Data[2][1];
00775         res.Z = in_rhs.X * m_Data[0][2] + in_rhs.Y * m_Data[1][2] + in_rhs.Z * m_Data[2][2];
00776         return res;
00777     }
00778 
00779     AkForceInline AkMatrix3x3& operator+=(const AkMatrix3x3& in_rhs)
00780     {
00781         Add(*this, *this, in_rhs);
00782         return *this;
00783     }
00784 
00785     static AkForceInline void Add(AkMatrix3x3& out_res, const AkMatrix3x3& in_m0, const AkMatrix3x3& in_m1)
00786     {
00787 #define ADD(i,j) out_res(i,j) = in_m0(i,j) + in_m1(i,j)
00788         ADD(0, 0); ADD(0, 1); ADD(0, 2);
00789         ADD(1, 0); ADD(1, 1); ADD(1, 2);
00790         ADD(2, 0); ADD(2, 1); ADD(2, 2);
00791 #undef ADD
00792     }
00793 
00794     AkForceInline AkMatrix3x3& operator*=(const AkReal32& in_f)
00795     {
00796         m_Data[0][0] *= in_f; m_Data[0][1] *= in_f; m_Data[0][2] *= in_f;
00797         m_Data[1][0] *= in_f; m_Data[1][1] *= in_f; m_Data[1][2] *= in_f;
00798         m_Data[2][0] *= in_f; m_Data[2][1] *= in_f; m_Data[2][2] *= in_f;
00799         return *this;
00800     }
00801 
00802     static AkForceInline void Diagonal(AkMatrix3x3& out_mat, AkReal32 in_f)
00803     {
00804         out_mat(0, 0) = in_f;       out_mat(0, 1) = 0.f;        out_mat(0, 2) = 0.f;
00805         out_mat(1, 0) = 0.f;        out_mat(1, 1) = in_f;       out_mat(1, 2) = 0.f;
00806         out_mat(2, 0) = 0.f;        out_mat(2, 1) = 0.f;        out_mat(2, 2) = in_f;
00807     }
00808 
00809     // Creates the matrix Mu such that Mu*v = u X v
00810     static AkForceInline  void CrossProductMatrix(AkMatrix3x3& out_mat, const Ak3DVector& in_u)
00811     {
00812         out_mat(0, 0) = 0.f;        out_mat(0, 1) = -in_u.Z;        out_mat(0, 2) = in_u.Y;
00813         out_mat(1, 0) = in_u.Z;     out_mat(1, 1) = 0.f;            out_mat(1, 2) = -in_u.X;
00814         out_mat(2, 0) = -in_u.Y;    out_mat(2, 1) = in_u.X;         out_mat(2, 2) = 0.f;
00815     }
00816 
00817     static AkForceInline void OuterProduct(AkMatrix3x3& out_mat, const Ak3DVector& in_v0, const Ak3DVector& in_v1)
00818     {
00819         out_mat(0, 0) = in_v0.X*in_v1.X;    out_mat(0, 1) = in_v0.X*in_v1.Y;        out_mat(0, 2) = in_v0.X*in_v1.Z;
00820         out_mat(1, 0) = in_v0.Y*in_v1.X;    out_mat(1, 1) = in_v0.Y*in_v1.Y;        out_mat(1, 2) = in_v0.Y*in_v1.Z;
00821         out_mat(2, 0) = in_v0.Z*in_v1.X;    out_mat(2, 1) = in_v0.Z*in_v1.Y;        out_mat(2, 2) = in_v0.Z*in_v1.Z;
00822     }
00823 
00824     static AkForceInline void Rotation(AkMatrix3x3& out_mat, AkReal32 in_angle, const Ak3DVector& in_axis)
00825     {
00826         Rotation(out_mat, sinf(in_angle), cosf(in_angle), in_axis);
00827     }
00828 
00829     static void Rotation(AkMatrix3x3& out_mat, AkReal32 in_sin, AkReal32 in_cos, const Ak3DVector& in_axis)
00830     {
00831         Diagonal(out_mat, in_cos);
00832 
00833         AkMatrix3x3 outer;
00834         OuterProduct(outer, in_axis, in_axis);
00835         outer *= (1.f - in_cos);
00836         out_mat += outer;
00837 
00838         AkMatrix3x3 cross;
00839         CrossProductMatrix(cross, in_axis*in_sin);
00840         out_mat += cross;
00841     }
00842 
00843     // [column][row]
00844     AkReal32 m_Data[3][3];
00845 };
00846 
00847 class AkQuaternion
00848 {
00849 public:
00850     // Identity quaternion
00851     AkQuaternion(): W(1.f), X(0.f), Y(0.f), Z(0.f) {}
00852 
00853     AkQuaternion(AkReal32 in_W, AkReal32 in_X, AkReal32 in_Y, AkReal32 in_Z) : 
00854             W(in_W), 
00855             X(in_X), 
00856             Y(in_Y), 
00857             Z(in_Z) 
00858     {}
00859 
00860     AkQuaternion(const Ak3DVector& in_fromVector): 
00861         W(0.f), 
00862         X(in_fromVector.X), 
00863         Y(in_fromVector.Y), 
00864         Z(in_fromVector.Z) 
00865     {}
00866 
00867     AkForceInline AkReal32 Length()
00868     {
00869         return sqrtf( W*W + X*X + Y*Y + Z*Z );
00870     }
00871 
00872     AkForceInline const AkQuaternion& Normalize()
00873     {
00874         AkReal32 f = 1.0f / Length();
00875         W *= f;
00876         X *= f;
00877         Y *= f;
00878         Z *= f;
00879         return *this;
00880     }
00881 
00882     AkForceInline AkQuaternion Inverse() const
00883     {
00884         AkReal32 norm = W*W + X*X + Y*Y + Z*Z;
00885         if (norm > 0.0)
00886         {
00887             AkReal32 invNorm = 1.0f / norm;
00888             return AkQuaternion(W*invNorm, -X*invNorm, -Y*invNorm, -Z*invNorm);
00889         }
00890         else
00891         {
00892             return AkQuaternion();
00893         }
00894     }
00895 
00896     // Create a quaternion representing the shortest arc rotation between (normalized) vectors v0, v1
00897     AkQuaternion(const Ak3DVector& in_v0, const Ak3DVector& in_v1)
00898     {
00899         AkReal32 dot = in_v0.Dot(in_v1);
00900         if (dot >= 1.0f - AKVECTORS_EPSILON)
00901         {
00902             // No rotation - return unity quaternion.
00903             AkQuaternion();
00904         }
00905         if (dot <= -1.f - AKVECTORS_EPSILON)
00906         {
00907             // 180 degree rotation - can use any non-zero length axis.
00908             Ak3DVector axis = Ak3DVector(0.f, 0.f, 1.f).Cross(in_v0);
00909             AkReal32 len = axis.Length();
00910             if (len < AKVECTORS_EPSILON)
00911             {
00912                 axis = Ak3DVector(0.f, 1.f, 0.f).Cross(in_v0);
00913                 len = axis.Length();
00914             }
00915             axis.Normalize();
00916             AkQuaternion(AKVECTORS_PI, axis);
00917         }
00918         else
00919         {
00920             AkReal32 sqrt = sqrtf((1.f + dot) * 2.f);
00921             AkReal32 invs = 1.f / sqrt;
00922 
00923             Ak3DVector cross = in_v0.Cross(in_v1);
00924 
00925             X = cross.X * invs;
00926             Y = cross.Y * invs;
00927             Z = cross.Z * invs;
00928             W = sqrt * 0.5f;
00929             Normalize();
00930         }
00931     }
00932     
00933     // Build quaternion from an axis and angle representation.
00934     AkQuaternion(AkReal32 in_angle, const Ak3DVector& in_axis)
00935     {
00936         AkReal32 cosHalfAngle = cosf(in_angle / 2.f);
00937         W = cosHalfAngle;
00938         X = cosHalfAngle*in_axis.X;
00939         Y = cosHalfAngle*in_axis.Y;
00940         Z = cosHalfAngle*in_axis.Z;
00941     }
00942     
00943     /// Quaternion multiplication.
00944     AkForceInline AkQuaternion operator*(const AkQuaternion& Q) const
00945     {
00946         return AkQuaternion(
00947             W*Q.W - X*Q.X - Y*Q.Y - Z*Q.Z,
00948             W*Q.X + X*Q.W + Y*Q.Z - Z*Q.Y,
00949             W*Q.Y - X*Q.Z + Y*Q.W + Z*Q.X,
00950             W*Q.Z + X*Q.Y - Y*Q.X + Z*Q.W);
00951     }
00952     
00953     AkForceInline Ak3DVector operator* (const Ak3DVector& in_v) const
00954     {
00955         /*
00956         // impl 1
00957         Ak3DVector uv, uuv;
00958         Ak3DVector qvec(X, Y, Z);
00959         uv = qvec.Cross(in_v);
00960         uuv = qvec.Cross(uv);
00961         uv *= (2.0f * W);
00962         uuv *= 2.0f;
00963         return in_v + uv + uuv;
00964         */
00965 
00966         // impl 2
00967         Ak3DVector u(X, Y, Z);
00968         Ak3DVector res = 
00969             u * u.Dot(in_v) * 2.f
00970             + in_v * (W*W - u.Dot(u))
00971             + u.Cross(in_v) * W * 2.0f;
00972 
00973         return res;
00974     }
00975 
00976     AkReal32 W;
00977     AkReal32 X;
00978     AkReal32 Y;
00979     AkReal32 Z;
00980 };
00981 
00982 struct AkIntersectionPoints
00983 {
00984     Ak3DVector points[2];
00985     AkUInt32 count;
00986 };
00987 
00988 class AkLine
00989 {
00990 public:
00991     AkLine()
00992     {
00993         mint = 1.175494351e-38F;
00994         maxt = 3.402823466e+38F;
00995     }
00996 
00997     AkLine(
00998         Ak3DVector                  in_L,
00999         Ak3DVector                  in_P
01000         )
01001     {
01002         L = in_L;
01003         P = in_P;
01004         mint = 1.175494351e-38F;
01005         maxt = 3.402823466e+38F;
01006     }
01007 
01008     Ak3DVector PointAt(AkReal32 t) const
01009     {
01010         return P + L*t;
01011     }
01012 
01013     bool Intersect(
01014         Ak3DVector A,
01015         Ak3DVector B)
01016     {
01017         Ak3DVector L2 = B - A;
01018 
01019         /*
01020         a (V1 X V2) = (P2 - P1) X V2
01021         If the lines intersect at a single point, then the resultant vectors
01022         on each side of this equation must be parallel, and the left side must
01023         not be the zero vector. We should check to make sure that this is
01024         true. Once we have checked this, we can solve for 'a' by taking the
01025         magnitude of each side and dividing. If the resultant vectors are
01026         parallel, but in opposite directions, then 'a' is the negative of the
01027         ratio of magnitudes. Once we have 'a' we can go back to the equation
01028         for L1 to find the intersection point.
01029         */
01030         Ak3DVector V1 = L;
01031         Ak3DVector V2 = B - A;
01032         Ak3DVector P1 = P;
01033         Ak3DVector P2 = A;
01034 
01035         // k(V1 X V2) = (A - P) X V2
01036 
01037         Ak3DVector v1CrossV2 = V1.Cross(V2);
01038         AkReal32 det = Ak3DVector::Determinant(
01039             P2 - P1,
01040             V2,
01041             v1CrossV2
01042             );
01043         AkReal32 t = det / v1CrossV2.LengthSquared();
01044 
01045         det = Ak3DVector::Determinant(
01046             P2 - P1,
01047             V1,
01048             v1CrossV2
01049             );
01050         AkReal32 s = det / v1CrossV2.LengthSquared();
01051 
01052         AkReal32 distsqrd = ((P2 + V2*s) - (P1 + V1*t)).LengthSquared();
01053 
01054         if ((AkReal32)fabs(v1CrossV2.L2_Norm()) >= AKVECTORS_EPSILON
01055             && distsqrd < 0.001
01056             && s <= 1.0f )
01057         {
01058 #ifdef AKPORTALS_DEBUG
01059             Ak3DVector minPoint = PointAt(t);
01060 
01061             char msg[256];
01062             sprintf(msg, "L1a=[%0.2f,%0.2f,%0.2f];\n", P.X, P.Y, P.Z); AKPLATFORM::OutputDebugMsg(msg);
01063             sprintf(msg, "L1b=[%0.2f,%0.2f,%0.2f];\n", V1.X + P.X, V1.Y + P.Y, V1.Z + P.Z); AKPLATFORM::OutputDebugMsg(msg);
01064             sprintf(msg, "L2a=[%0.2f,%0.2f,%0.2f];\n", A.X, A.Y, A.Z); AKPLATFORM::OutputDebugMsg(msg);
01065             sprintf(msg, "L2b=[%0.2f,%0.2f,%0.2f];\n", B.X, B.Y, B.Z); AKPLATFORM::OutputDebugMsg(msg);
01066             sprintf(msg, "%% t=%0.2f Min t=%0.2f, Max t=%0.2f\n", t, mint, maxt); AKPLATFORM::OutputDebugMsg(msg);
01067             sprintf(msg, "intrPoint=[%0.2f,%0.2f,%0.2f];\n", minPoint.X, minPoint.Y, minPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
01068             sprintf(msg, "\n"); AKPLATFORM::OutputDebugMsg(msg);
01069 #endif
01070 
01071             mint = AkMin(mint, t);
01072             maxt = AkMax(maxt, t);
01073             
01074             return true;
01075         }
01076 
01077 #ifdef AKPORTALS_DEBUG
01078     //  char msg[256];
01079     //  sprintf(msg, "%% DISCARTED t=%0.2f Min t=%0.2f, Max t=%0.2f\n", t, mint, maxt); AKPLATFORM::OutputDebugMsg(msg);
01080 #endif
01081         return false;
01082     }
01083 
01084     Ak3DVector L;
01085     Ak3DVector P;
01086 
01087     AkReal32 mint;
01088     AkReal32 maxt;
01089 };
01090 
01091 class AkPlane
01092 {
01093 public:
01094     AkPlane()
01095     {
01096     }
01097 
01098     AkPlane(
01099         Ak3DVector                  in_p1,
01100         Ak3DVector                  in_p2,
01101         Ak3DVector                  in_p4
01102         )
01103     {
01104         SetPlane(
01105             in_p1,
01106             in_p2,
01107             in_p4);
01108     }
01109 
01110     ~AkPlane()
01111     {
01112     }
01113 
01114     void SetPlane(
01115         Ak3DVector                  in_p1,
01116         Ak3DVector                  in_p2,
01117         Ak3DVector                  in_p4
01118         )
01119     {
01120         // Reorder A-B-C to clockwwise if necessary
01121         AKASSERT(in_p1.X < 100000 && in_p1.X > -100000);
01122         AKASSERT(in_p1.Y < 100000 && in_p1.Y > -100000);
01123         AKASSERT(in_p1.Z < 100000 && in_p1.Z > -100000);
01124 
01125         AKASSERT(in_p2.X < 100000 && in_p2.X > -100000);
01126         AKASSERT(in_p2.Y < 100000 && in_p2.Y > -100000);
01127         AKASSERT(in_p2.Z < 100000 && in_p2.Z > -100000);
01128 
01129         AKASSERT(in_p4.X < 100000 && in_p4.X > -100000);
01130         AKASSERT(in_p4.Y < 100000 && in_p4.Y > -100000);
01131         AKASSERT(in_p4.Z < 100000 && in_p4.Z > -100000);
01132 
01133         p1 = in_p1;
01134         p2 = in_p2;
01135         p4 = in_p4;
01136 
01137         SetNormal();
01138 
01139         // Ax + By + Cz + D = 0
01140         // Find D using the normal and a point
01141         D = -(N.X*p1.X) - (N.Y*p1.Y) - (N.Z*p1.Z);
01142     }
01143 
01144 #define EPSILON 0.01f
01145     bool DoesRayIntersect(
01146         const Ak3DVector&           in_Origin,
01147         const Ak3DVector&           in_Destination,
01148         Ak3DVector&                 out_Intersection
01149         ) const
01150     {
01151         AkReal32 A = N.X;
01152         AkReal32 B = N.Y;
01153         AkReal32 C = N.Z;
01154 
01155         Ak3DVector ray = in_Destination - in_Origin;
01156         AkReal32 rayLength = ray.Length();
01157 
01158         Ak3DVector intersect;
01159 
01160         // If ray is < EPSILON, use on of the point directly for the test and skip the linear projection
01161         if (rayLength <= EPSILON)
01162         {
01163             Ak3DVector temp = in_Origin - p1;
01164             AkReal32 dot = temp.DotProduct(N);
01165             if (dot < EPSILON && dot > -EPSILON)
01166             {
01167                 intersect = in_Origin;
01168             }
01169             else
01170             {
01171                 // For debug only, to remove
01172                 out_Intersection = p1;
01173                 return false;
01174             }
01175 
01176         }
01177         else
01178         {
01179             // Normalize ray
01180             ray.Normalize();
01181 
01182             // TODO: possible fix for all edge cases
01183             // 1) if ray len ~= 0, only check if one of the point is on target, ie: assign the intersect point
01184 
01185             // Is ray parallel to the plane?
01186             if ((A*ray.X + B*ray.Y + C*ray.Z) == 0.0f)
01187             {
01188                 // For debug only, to remove
01189                 AkReal32 t = -(A*in_Origin.X + B*in_Origin.Y + C*in_Origin.Z + D) / (A*ray.X + B*ray.Y + C*ray.Z);
01190                 intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
01191                 out_Intersection = intersect; // For debugging
01192                 return false;
01193             }
01194 
01195 
01196             // Distance along the ray where reflector is hit
01197             AkReal32 t = -(A*in_Origin.X + B*in_Origin.Y + C*in_Origin.Z + D) / (A*ray.X + B*ray.Y + C*ray.Z);
01198 
01199             // Is the ray going towards the plane? Is it long enough?
01200             if (t < -EPSILON || t >(rayLength + EPSILON))
01201             {
01202                 // For debug only, to remove
01203                 intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
01204                 out_Intersection = intersect; // For debugging
01205                 return false; // The ray doesn't intersect
01206             }
01207 
01208             // Find the coordinate of intersection on the plane
01209             intersect = Ak3DVector(in_Origin.X + ray.X*t, in_Origin.Y + ray.Y*t, in_Origin.Z + ray.Z*t);
01210         }
01211         ///////////////////////////////////////
01212         //
01213         //      p2____v3____p3
01214         //      |     .     |
01215         //      ^   inter   v4
01216         //      v1          v
01217         //      |           |
01218         //      p1__ v2>___p4
01219 
01220         Ak3DVector v1 = p2 - p1;
01221         Ak3DVector v2 = p4 - p1;
01222         Ak3DVector vInter1 = intersect - p1;
01223 
01224         Ak3DVector p3 = p4 + v1;
01225         Ak3DVector v3 = p2 - p3;
01226         Ak3DVector v4 = p4 - p3;
01227         Ak3DVector vInter2 = intersect - p3;
01228 
01229         v1.Normalize(); v2.Normalize(); v3.Normalize(); v4.Normalize(); vInter1.Normalize(); vInter2.Normalize();
01230 
01231         // Since it's a square, the angle between the point of intersection and any segment of the pannel should be < 90 degree,
01232         // therefore the dot product of the two normalized vectors should be > 0
01233         AkReal32 dot1 = v1.DotProduct(vInter1);
01234         AkReal32 dot2 = v2.DotProduct(vInter1);
01235         AkReal32 dot3 = v3.DotProduct(vInter2);
01236         AkReal32 dot4 = v4.DotProduct(vInter2);
01237 
01238         out_Intersection = intersect;
01239 
01240         return dot1 >= -EPSILON && dot2 >= -EPSILON && dot3 >= -EPSILON && dot4 >= -EPSILON;
01241     }
01242 
01243     AkReal32 DistPoint_to_Plane(
01244         Ak3DVector          in_P,
01245         Ak3DVector&         out_B) const
01246     {
01247         AkReal32 distance = (AkReal32)(AkReal32)fabs(N.X * in_P.X + N.Y * in_P.Y + N.Z * in_P.Z + D);
01248 
01249         Ak3DVector pointToPlane = N;
01250         pointToPlane *= distance;
01251 
01252         out_B = in_P + pointToPlane;
01253 
01254         return (AkReal32)fabs(distance);
01255     }
01256 
01257     void SetReflection(
01258         AkReal32*           out_mat) const
01259     {
01260         // http://ami.ektf.hu/uploads/papers/finalpdf/AMI_40_from175to186.pd
01261         /* m_pReflectionMatrix
01262         reflection on z axis
01263 
01264         P0 (x0, y0, z0), P1 (x1, y1, z1) and P2 (x2, y2, z2),
01265         normal = (cx, cy, cz)
01266         d = -CxX0 - CyY0 - CzZ0
01267 
01268         Reflect =   1-2Cx^2     -2CxCy      -2CxCz      -2Cxd
01269         -2CxCy      1-2Cy^2     -2CyCz      -2Cyd
01270         -2CxCz      -2CyCz      1-2Cz^2     -2Czd
01271         0           0           0           1
01272         */
01273 
01274         AkReal32 d = -(N.X*p1.X) - (N.Y*p1.Y) - (N.Z*p1.Z);
01275 
01276         out_mat[0] = 1 - 2 * N.X*N.X;       out_mat[1] = -2 * N.X*N.Y;              out_mat[2] = -2 * N.X*N.Z;              out_mat[3] = -2 * N.X*d;
01277         out_mat[0 + 4] = -2 * N.X*N.Y;      out_mat[1 + 4] = 1 - 2 * N.Y*N.Y;       out_mat[2 + 4] = -2 * N.Y*N.Z;          out_mat[3 + 4] = -2 * N.Y*d;
01278         out_mat[0 + 8] = -2 * N.X*N.Z;      out_mat[1 + 8] = -2 * N.Y*N.Z;          out_mat[2 + 8] = 1 - 2 * N.Z*N.Z;       out_mat[3 + 8] = -2 * N.Z*d;
01279         out_mat[0 + 12] = 0;                out_mat[1 + 12] = 0;                    out_mat[2 + 12] = 0;                    out_mat[3 + 12] = 1;
01280     }
01281 
01282     Ak3DVector GetN() const { return N; }
01283     AkReal32 GetD() const { return D; }
01284 
01285     bool FindIntersectionPoints(
01286         const AkPlane& in_PlaneB,
01287         AkIntersectionPoints& out_Intrs) const
01288     {
01289         out_Intrs.count = 0;
01290 
01291         // Use vector to solve A
01292 
01293         Ak3DVector point;
01294 
01295         Ak3DVector N1 = N;
01296         Ak3DVector N2 = in_PlaneB.GetN();
01297         AkReal32 D1 = D;
01298         AkReal32 D2 = in_PlaneB.GetD();
01299 
01300         Ak3DVector L = N1.Cross(N2);
01301         if (L.Length() < 0.001f)
01302         {
01303             return false; // The two planes are parallel
01304         }
01305 
01306         AkUInt8 pivotAxis = 0;
01307 
01308         if ((AkReal32)fabs(L.Y) > (AkReal32)fabs(L.X))
01309         {
01310             pivotAxis = 1;
01311             if ((AkReal32)fabs(L.Z) > (AkReal32)fabs(L.Y))
01312             {
01313                 pivotAxis = 2;
01314             }
01315         }
01316         else if ((AkReal32)fabs(L.Z) > (AkReal32)fabs(L.X))
01317         {
01318             pivotAxis = 2;
01319         }
01320 
01321         /*
01322         Pu = ( N1v*D2 - N2v*D1 ) / Lw
01323         Pv = ( N2u*D1 - N1u*D2 ) / Lw
01324         Pz = 0
01325         */
01326 
01327         switch (pivotAxis)
01328         {
01329         case 0:
01330             AKASSERT((AkReal32)fabs(L.X) > AKVECTORS_EPSILON);
01331             point.X = 0.f;
01332             point.Y = (N1.Z*D2 - N2.Z*D1) / L.X;
01333             point.Z = (N2.Y*D1 - N1.Y*D2) / L.X;
01334             break;
01335         case 1:
01336             AKASSERT((AkReal32)fabs(L.Y) > AKVECTORS_EPSILON);
01337             point.X = (N1.Z*D2 - N2.Z*D1) / L.Y;
01338             point.Y = 0.f;
01339             point.Z = (N2.X*D1 - N1.X*D2) / L.Y;
01340             break;
01341         case 2:
01342             AKASSERT((AkReal32)fabs(L.Z) > AKVECTORS_EPSILON);
01343             point.X = (N1.Y*D2 - N2.Y*D1) / L.Z;
01344             point.Y = (N2.X*D1 - N1.X*D2) / L.Z;
01345             point.Z = 0.f;
01346             break;
01347         };
01348 
01349 
01350 
01351         L.Normalize();
01352 
01353         AkLine intrLine = AkLine(L, point);
01354         AkLine intrLine2 = AkLine(L, point);
01355 
01356         //in_PlaneB.GetP1()
01357 
01358         // find min max
01359         AkUInt32 cpt = 0;
01360         AkUInt32 cpt2 = 0;
01361         Ak3DVector p3 = GetP2() + (GetP4() - GetP1());
01362 
01363 #ifdef AKPORTALS_DEBUG
01364         char msg[256];
01365         sprintf(msg, "P1a=[%0.2f,%0.2f,%0.2f];\n", GetP1().X, GetP1().Y, GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01366         sprintf(msg, "P2a=[%0.2f,%0.2f,%0.2f];\n", GetP2().X, GetP2().Y, GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01367         sprintf(msg, "P4a=[%0.2f,%0.2f,%0.2f];\n", GetP4().X, GetP4().Y, GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01368 
01369         sprintf(msg, "P1b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP1().X, in_PlaneB.GetP1().Y, in_PlaneB.GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01370         sprintf(msg, "P2b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP2().X, in_PlaneB.GetP2().Y, in_PlaneB.GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01371         sprintf(msg, "P4b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP4().X, in_PlaneB.GetP4().Y, in_PlaneB.GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01372 
01373         sprintf(msg, "line1=[%0.2f,%0.2f,%0.2f];\n", point.X + L.X*1000.f, point.Y + L.Y*1000.f, point.Z + L.Z*1000.f); AKPLATFORM::OutputDebugMsg(msg);
01374         sprintf(msg, "line2=[%0.2f,%0.2f,%0.2f];\n", point.X - L.X*1000.f, point.Y - L.Y*500.f, point.Z - L.Z*500.f); AKPLATFORM::OutputDebugMsg(msg);
01375 
01376 
01377         sprintf(msg, "%% Plane intersec\n"); AKPLATFORM::OutputDebugMsg(msg);
01378 #endif
01379         // for the four lines in rectangle
01380         // Find where the line is crossing with plane A
01381         if (intrLine.Intersect(GetP1(), GetP2())) cpt++;
01382         if (intrLine.Intersect(GetP1(), GetP4())) cpt++;
01383         if (intrLine.Intersect(GetP2(), p3)) cpt++;
01384         if (intrLine.Intersect(p3, GetP4())) cpt++;
01385         //AKASSERT(cpt == 2);
01386 
01387 #ifdef AKPORTALS_DEBUG
01388         sprintf(msg, "%% Portal intersec\n"); AKPLATFORM::OutputDebugMsg(msg);
01389 #endif
01390 
01391         // Find where the line is crossing with plane B
01392         p3 = in_PlaneB.GetP2() + (in_PlaneB.GetP4() - in_PlaneB.GetP1());
01393         if (intrLine2.Intersect(in_PlaneB.GetP1(), in_PlaneB.GetP2())) cpt2++;
01394         if (intrLine2.Intersect(in_PlaneB.GetP1(), in_PlaneB.GetP4())) cpt2++;
01395         if (intrLine2.Intersect(in_PlaneB.GetP2(), p3)) cpt2++;
01396         if (intrLine2.Intersect(p3, in_PlaneB.GetP4())) cpt2++;
01397         // **AKASSERT(cpt2 == 2 || cpt == 2);
01398 
01399         if (cpt < 2 || cpt2 < 2)
01400         {
01401 #ifdef AKPORTALS_DEBUG
01402             sprintf(msg, "%% NON \n"); AKPLATFORM::OutputDebugMsg(msg);
01403             sprintf(msg, "%% _______________________\n"); AKPLATFORM::OutputDebugMsg(msg);
01404 #endif
01405             return false;
01406         }
01407 
01408         AkReal32 start = AkMax(intrLine.mint, intrLine2.mint);
01409         AkReal32 end = AkMin(intrLine.maxt, intrLine2.maxt);
01410 
01411         Ak3DVector minPoint = intrLine.PointAt(start);
01412         Ak3DVector maxPoint = intrLine.PointAt(end);
01413 #ifdef AKPORTALS_DEBUG
01414         sprintf(msg, "P1a=[%0.2f,%0.2f,%0.2f];\n", GetP1().X, GetP1().Y, GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01415         sprintf(msg, "P2a=[%0.2f,%0.2f,%0.2f];\n", GetP2().X, GetP2().Y, GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01416         sprintf(msg, "P4a=[%0.2f,%0.2f,%0.2f];\n", GetP4().X, GetP4().Y, GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01417 
01418         sprintf(msg, "P1b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP1().X, in_PlaneB.GetP1().Y, in_PlaneB.GetP1().Z); AKPLATFORM::OutputDebugMsg(msg);
01419         sprintf(msg, "P2b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP2().X, in_PlaneB.GetP2().Y, in_PlaneB.GetP2().Z); AKPLATFORM::OutputDebugMsg(msg);
01420         sprintf(msg, "P4b=[%0.2f,%0.2f,%0.2f];\n", in_PlaneB.GetP4().X, in_PlaneB.GetP4().Y, in_PlaneB.GetP4().Z); AKPLATFORM::OutputDebugMsg(msg);
01421 
01422         sprintf(msg, "line1=[%0.2f,%0.2f,%0.2f];\n", point.X + L.X*1000.f, point.Y + L.Y*1000.f, point.Z + L.Z*1000.f); AKPLATFORM::OutputDebugMsg(msg);
01423         sprintf(msg, "line2=[%0.2f,%0.2f,%0.2f];\n", point.X - L.X*1000.f, point.Y - L.Y*500.f, point.Z - L.Z*500.f); AKPLATFORM::OutputDebugMsg(msg);
01424 
01425         sprintf(msg, "intr1=[%0.2f,%0.2f,%0.2f];\n", minPoint.X, minPoint.Y, minPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
01426         sprintf(msg, "intr2=[%0.2f,%0.2f,%0.2f];\n", maxPoint.X, maxPoint.Y, maxPoint.Z); AKPLATFORM::OutputDebugMsg(msg);
01427 
01428         sprintf(msg, "%% _______________________\n"); AKPLATFORM::OutputDebugMsg(msg);
01429 #endif
01430         out_Intrs.points[0] = minPoint;
01431         out_Intrs.points[1] = maxPoint;
01432         out_Intrs.count = 2;
01433 
01434         return true;
01435     }
01436 
01437     Ak3DVector GetP1() const { return p1; }
01438     Ak3DVector GetP2() const { return p2; }
01439     Ak3DVector GetP4() const { return p4; }
01440 
01441 private:
01442     bool SetNormal()
01443     {
01444         //m_pNormal = (B-A) cross (C-A); normalize
01445         Ak3DVector a = p2 - p1;
01446         Ak3DVector b = p4 - p1;
01447 
01448         N = Ak3DVector(a.Y*b.Z - a.Z*b.Y, -(a.X*b.Z - a.Z*b.X), a.X*b.Y - a.Y*b.X);
01449 
01450         AkReal32 len = N.Length();
01451         AKASSERT(len > 0.f);
01452 
01453         if (len > 0)
01454         {
01455             N /= len;
01456         }
01457         else
01458         {
01459             // TODO handle invalid reflectors
01460             return false;
01461         }
01462 
01463         return true;
01464     };
01465 
01466     /*
01467     p2__________p3
01468     |     .     |
01469     ^   inter   v3
01470     v1          v
01471     |           |
01472     p1__ v2>___p4
01473     */
01474 
01475     Ak3DVector                      p1;     // Bottom left
01476     Ak3DVector                      p2;     // Top left
01477     Ak3DVector                      p4;     // Tottom right
01478     Ak3DVector                      N;      // Normal vector
01479     AkReal32                        D;      // Plane equation: Ax + By + Cz = D => N.Xx + N.Yy + N.Zz = D
01480 };
01481 
01482 struct AkBoundingBox
01483 {
01484     AkBoundingBox() :
01485         m_Min(Ak3DVector(FLT_MAX, FLT_MAX, FLT_MAX)),
01486         m_Max(Ak3DVector(-FLT_MAX, -FLT_MAX, -FLT_MAX))
01487     {}
01488 
01489     void Update(
01490         const Ak3DVector &      in_point
01491         )
01492     {
01493         if (m_Min.X > in_point.X)
01494             m_Min.X = in_point.X;
01495 
01496         if (m_Min.Y > in_point.Y)
01497             m_Min.Y = in_point.Y;
01498 
01499         if (m_Min.Z > in_point.Z)
01500             m_Min.Z = in_point.Z;
01501 
01502         if (m_Max.X < in_point.X)
01503             m_Max.X = in_point.X;
01504 
01505         if (m_Max.Y < in_point.Y)
01506             m_Max.Y = in_point.Y;
01507 
01508         if (m_Max.Z < in_point.Z)
01509             m_Max.Z = in_point.Z;
01510     }
01511 
01512     AkForceInline bool IsWithin(
01513         const Ak3DVector &      in_Point
01514         ) const
01515     {
01516         return in_Point >= m_Min && in_Point <= m_Max;
01517     }
01518 
01519     AkForceInline bool IsWithin(
01520         const AkBoundingBox &   in_BB
01521         ) const
01522     {
01523         return (m_Min.X <= in_BB.m_Max.X && m_Max.X >= in_BB.m_Min.X) &&
01524             (m_Min.Y <= in_BB.m_Max.Y && m_Max.Y >= in_BB.m_Min.Y) &&
01525             (m_Min.Z <= in_BB.m_Max.Z && m_Max.Z >= in_BB.m_Min.Z);
01526     }
01527 
01528     AkBoundingBox Intersect(
01529         const AkBoundingBox &   in_BB
01530     ) const
01531     {
01532         AkBoundingBox result;
01533         
01534         result.m_Max.X = AkMin(m_Max.X, in_BB.m_Max.X);
01535         result.m_Max.Y = AkMin(m_Max.Y, in_BB.m_Max.Y);
01536         result.m_Max.Z = AkMin(m_Max.Z, in_BB.m_Max.Z);
01537 
01538         result.m_Min.X = AkMax(m_Min.X, in_BB.m_Min.X);
01539         result.m_Min.Y = AkMax(m_Min.Y, in_BB.m_Min.Y);
01540         result.m_Min.Z = AkMax(m_Min.Z, in_BB.m_Min.Z);
01541         
01542         return result;
01543     }
01544 
01545     // returns acos(in_fAngle)
01546     AkForceInline AkReal32 ACos(
01547         AkReal32            in_fAngle
01548         ) const
01549     {
01550         AKASSERT((in_fAngle <= 1.0f) && (in_fAngle >= -1.0f));
01551         return acosf(in_fAngle);
01552     }
01553 
01554     AkForceInline bool IsEmpty() const
01555     {
01556         return (m_Min.X >= m_Max.X) || (m_Min.Y >= m_Max.Y) || (m_Min.Z >= m_Max.Z);
01557     }
01558 
01559     Ak3DVector                      m_Min;
01560     Ak3DVector                      m_Max;
01561 };
01562 
01563 class AkBox
01564 {
01565 public:
01566     AkBox()
01567     {
01568     }
01569 
01570     ~AkBox()
01571     {
01572     }
01573 
01574     void Init(
01575         const Ak3DVector &      in_center,
01576         const Ak3DVector &      in_extent,
01577         const Ak3DVector &      in_Front,
01578         const Ak3DVector &      in_Up)
01579     {
01580         AKASSERT(fabs(in_Front.Length() - 1.f) < 0.001 && fabs(in_Up.Length() - 1.f) < 0.001);//Must be unit vectors.
01581         AKASSERT(fabs(in_Front.Dot(in_Up) - 0.f) < 0.001); //Must be orthogonal.
01582 
01583         m_Center = in_center;
01584         m_Extent = in_extent;
01585 
01586         m_Z = in_Front;
01587         m_Y = in_Up;
01588         m_X = m_Z.Cross(m_Y);
01589     }
01590 
01591     bool IsPointInBox(
01592         const Ak3DVector &      in_Point
01593         ) const
01594     {
01595         Ak3DVector pt = in_Point - m_Center;
01596         return  fabs(pt.Dot(m_X)) <= m_Extent.X && fabs(pt.Dot(m_Y)) <= m_Extent.Y && fabs(pt.Dot(m_Z)) <= m_Extent.Z;
01597     }
01598 
01599     Ak3DVector GetSize() const { return m_Extent*2.f; }
01600     Ak3DVector GetCenter() const { return m_Center; }
01601 
01602     Ak3DVector GetUx() const { return m_X; }
01603     Ak3DVector GetUy() const { return m_Y; }
01604     Ak3DVector GetUz() const { return m_Z; }
01605 
01606     Ak3DVector GetFront() const { return m_Z; }
01607     Ak3DVector GetUp() const { return m_Y; }
01608     Ak3DVector GetSide() const { return m_X; }
01609 
01610     AkReal32 GetVolume() const
01611     {
01612         Ak3DVector size = GetSize();
01613         return size.X * size.Y * size.Z;
01614     }
01615 
01616     bool SeparatingAxisExists(
01617         const Ak3DVector&       L,
01618         const AkBox&            B
01619         ) const
01620     {
01621         // Separating Axis Theorem for Oriented Bounding Boxes by Johnny Huynh
01622         const AkBox& A = *this;
01623         Ak3DVector T = B.GetCenter() - A.GetCenter();
01624 
01625         AkReal32 WA = A.m_Extent.X;
01626         AkReal32 HA = A.m_Extent.Y;
01627         AkReal32 DA = A.m_Extent.Z;
01628 
01629         AkReal32 WB = B.m_Extent.X;
01630         AkReal32 HB = B.m_Extent.Y;
01631         AkReal32 DB = B.m_Extent.Z;
01632 
01633         Ak3DVector Ax = A.GetUx();
01634         Ak3DVector Ay = A.GetUy();
01635         Ak3DVector Az = A.GetUz();
01636 
01637         Ak3DVector Bx = B.GetUx();
01638         Ak3DVector By = B.GetUy();
01639         Ak3DVector Bz = B.GetUz();
01640 
01641         /*
01642         | T • L | > | (WA*Ax) • L | + | (HA*Ay) • L | + |(DA*Az) • L | +
01643                     | (WB*Bx) • L | +| (HB*By) • L | +| (DB*Bz) • L |*/
01644 
01645         AkReal32 left = (AkReal32)fabs(T.DotProduct(L));
01646         AkReal32 dpax = (AkReal32)fabs((Ax*WA).DotProduct(L));
01647         AkReal32 dpay = (AkReal32)fabs((Ay*HA).DotProduct(L));
01648         AkReal32 dpaz = (AkReal32)fabs((Az*DA).DotProduct(L));
01649         AkReal32 dpbx = (AkReal32)fabs((Bx*WB).DotProduct(L));
01650         AkReal32 dpby = (AkReal32)fabs((By*HB).DotProduct(L));
01651         AkReal32 dpbz = (AkReal32)fabs((Bz*DB).DotProduct(L));
01652 
01653         AkReal32 right = dpax + dpay + dpaz + dpbx + dpby + dpbz;
01654 
01655         return left > right;
01656     }
01657 
01658     void UpdateBoundingBox(AkBoundingBox& out_aabb) const
01659     {
01660         Ak3DVector x = m_X * m_Extent.X;
01661         out_aabb.Update(m_Center + x);
01662         out_aabb.Update(m_Center - x);
01663         Ak3DVector y = m_Y * m_Extent.Y;
01664         out_aabb.Update(m_Center + y);
01665         out_aabb.Update(m_Center - y);
01666         Ak3DVector Z = m_Z * m_Extent.Z;
01667         out_aabb.Update(m_Center + Z);
01668         out_aabb.Update(m_Center - Z);
01669     }
01670 
01671 
01672 private:
01673 
01674     Ak3DVector                      m_Center;
01675     Ak3DVector                      m_Extent;
01676 
01677     //Orthonormal Axes
01678     Ak3DVector                      m_X;
01679     Ak3DVector                      m_Y;
01680     Ak3DVector                      m_Z;
01681 };