Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: sandbox_light/src/external/ogremath/OgreMath.cpp @ 6639

Last change on this file since 6639 was 5789, checked in by rgrieder, 15 years ago

Stripped sandbox further down to get a light version that excludes almost all core features.
Also, the Ogre dependency has been removed and a little ogremath library been added.

  • Property svn:eol-style set to native
File size: 14.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30#include "OgreMath.h"
31#include "asm_math.h"
32#include "OgreVector2.h"
33#include "OgreVector3.h"
34#include "OgreVector4.h"
35#include "OgreMatrix4.h"
36
37
38namespace Ogre
39{
40
41    const Real Math::POS_INFINITY = std::numeric_limits<Real>::infinity();
42    const Real Math::NEG_INFINITY = -std::numeric_limits<Real>::infinity();
43    const Real Math::PI = Real( 4.0 * atan( 1.0 ) );
44    const Real Math::TWO_PI = Real( 2.0 * PI );
45    const Real Math::HALF_PI = Real( 0.5 * PI );
46        const Real Math::fDeg2Rad = PI / Real(180.0);
47        const Real Math::fRad2Deg = Real(180.0) / PI;
48
49    int Math::mTrigTableSize;
50   Math::AngleUnit Math::msAngleUnit;
51
52    Real  Math::mTrigTableFactor;
53    Real *Math::mSinTable = NULL;
54    Real *Math::mTanTable = NULL;
55
56    //-----------------------------------------------------------------------
57    Math::Math( unsigned int trigTableSize )
58    {
59        msAngleUnit = AU_DEGREE;
60
61        mTrigTableSize = trigTableSize;
62        mTrigTableFactor = mTrigTableSize / Math::TWO_PI;
63
64        mSinTable = static_cast<Real*>(malloc(mTrigTableSize * sizeof(Real)));
65        mTanTable = static_cast<Real*>(malloc(mTrigTableSize * sizeof(Real)));
66
67        buildTrigTables();
68    }
69
70    //-----------------------------------------------------------------------
71    Math::~Math()
72    {
73        free(mSinTable);
74        free(mTanTable);
75    }
76
77    //-----------------------------------------------------------------------
78    void Math::buildTrigTables(void)
79    {
80        // Build trig lookup tables
81        // Could get away with building only PI sized Sin table but simpler this
82        // way. Who cares, it'll ony use an extra 8k of memory anyway and I like
83        // simplicity.
84        Real angle;
85        for (int i = 0; i < mTrigTableSize; ++i)
86        {
87            angle = Math::TWO_PI * i / mTrigTableSize;
88            mSinTable[i] = sin(angle);
89            mTanTable[i] = tan(angle);
90        }
91    }
92        //-----------------------------------------------------------------------       
93        Real Math::SinTable (Real fValue)
94    {
95        // Convert range to index values, wrap if required
96        int idx;
97        if (fValue >= 0)
98        {
99            idx = int(fValue * mTrigTableFactor) % mTrigTableSize;
100        }
101        else
102        {
103            idx = mTrigTableSize - (int(-fValue * mTrigTableFactor) % mTrigTableSize) - 1;
104        }
105
106        return mSinTable[idx];
107    }
108        //-----------------------------------------------------------------------
109        Real Math::TanTable (Real fValue)
110    {
111        // Convert range to index values, wrap if required
112                int idx = int(fValue *= mTrigTableFactor) % mTrigTableSize;
113                return mTanTable[idx];
114    }
115    //-----------------------------------------------------------------------
116    int Math::ISign (int iValue)
117    {
118        return ( iValue > 0 ? +1 : ( iValue < 0 ? -1 : 0 ) );
119    }
120    //-----------------------------------------------------------------------
121    Radian Math::ACos (Real fValue)
122    {
123        if ( -1.0 < fValue )
124        {
125            if ( fValue < 1.0 )
126                return Radian(acos(fValue));
127            else
128                return Radian(0.0);
129        }
130        else
131        {
132            return Radian(PI);
133        }
134    }
135    //-----------------------------------------------------------------------
136    Radian Math::ASin (Real fValue)
137    {
138        if ( -1.0 < fValue )
139        {
140            if ( fValue < 1.0 )
141                return Radian(asin(fValue));
142            else
143                return Radian(HALF_PI);
144        }
145        else
146        {
147            return Radian(-HALF_PI);
148        }
149    }
150    //-----------------------------------------------------------------------
151    Real Math::Sign (Real fValue)
152    {
153        if ( fValue > 0.0 )
154            return 1.0;
155
156        if ( fValue < 0.0 )
157            return -1.0;
158
159        return 0.0;
160    }
161        //-----------------------------------------------------------------------
162        Real Math::InvSqrt(Real fValue)
163        {
164                return Real(asm_rsq(fValue));
165        }
166    //-----------------------------------------------------------------------
167    Real Math::UnitRandom ()
168    {
169        return asm_rand() / asm_rand_max();
170    }
171   
172    //-----------------------------------------------------------------------
173    Real Math::RangeRandom (Real fLow, Real fHigh)
174    {
175        return (fHigh-fLow)*UnitRandom() + fLow;
176    }
177
178    //-----------------------------------------------------------------------
179    Real Math::SymmetricRandom ()
180    {
181                return 2.0f * UnitRandom() - 1.0f;
182    }
183
184   //-----------------------------------------------------------------------
185    void Math::setAngleUnit(Math::AngleUnit unit)
186   {
187       msAngleUnit = unit;
188   }
189   //-----------------------------------------------------------------------
190   Math::AngleUnit Math::getAngleUnit(void)
191   {
192       return msAngleUnit;
193   }
194    //-----------------------------------------------------------------------
195    Real Math::AngleUnitsToRadians(Real angleunits)
196    {
197       if (msAngleUnit == AU_DEGREE)
198           return angleunits * fDeg2Rad;
199       else
200           return angleunits;
201    }
202
203    //-----------------------------------------------------------------------
204    Real Math::RadiansToAngleUnits(Real radians)
205    {
206       if (msAngleUnit == AU_DEGREE)
207           return radians * fRad2Deg;
208       else
209           return radians;
210    }
211
212    //-----------------------------------------------------------------------
213    Real Math::AngleUnitsToDegrees(Real angleunits)
214    {
215       if (msAngleUnit == AU_RADIAN)
216           return angleunits * fRad2Deg;
217       else
218           return angleunits;
219    }
220
221    //-----------------------------------------------------------------------
222    Real Math::DegreesToAngleUnits(Real degrees)
223    {
224       if (msAngleUnit == AU_RADIAN)
225           return degrees * fDeg2Rad;
226       else
227           return degrees;
228    }
229
230    //-----------------------------------------------------------------------
231        bool Math::pointInTri2D(const Vector2& p, const Vector2& a, 
232                const Vector2& b, const Vector2& c)
233    {
234                // Winding must be consistent from all edges for point to be inside
235                Vector2 v1, v2;
236                Real dot[3];
237                bool zeroDot[3];
238
239                v1 = b - a;
240                v2 = p - a;
241
242                // Note we don't care about normalisation here since sign is all we need
243                // It means we don't have to worry about magnitude of cross products either
244                dot[0] = v1.crossProduct(v2);
245                zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3);
246
247
248                v1 = c - b;
249                v2 = p - b;
250
251                dot[1] = v1.crossProduct(v2);
252                zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3);
253
254                // Compare signs (ignore colinear / coincident points)
255                if(!zeroDot[0] && !zeroDot[1] 
256                && Math::Sign(dot[0]) != Math::Sign(dot[1]))
257                {
258                        return false;
259                }
260
261                v1 = a - c;
262                v2 = p - c;
263
264                dot[2] = v1.crossProduct(v2);
265                zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3);
266                // Compare signs (ignore colinear / coincident points)
267                if((!zeroDot[0] && !zeroDot[2] 
268                        && Math::Sign(dot[0]) != Math::Sign(dot[2])) ||
269                        (!zeroDot[1] && !zeroDot[2] 
270                        && Math::Sign(dot[1]) != Math::Sign(dot[2])))
271                {
272                        return false;
273                }
274
275
276                return true;
277    }
278        //-----------------------------------------------------------------------
279        bool Math::pointInTri3D(const Vector3& p, const Vector3& a, 
280                const Vector3& b, const Vector3& c, const Vector3& normal)
281        {
282        // Winding must be consistent from all edges for point to be inside
283                Vector3 v1, v2;
284                Real dot[3];
285                bool zeroDot[3];
286
287        v1 = b - a;
288        v2 = p - a;
289
290                // Note we don't care about normalisation here since sign is all we need
291                // It means we don't have to worry about magnitude of cross products either
292        dot[0] = v1.crossProduct(v2).dotProduct(normal);
293                zeroDot[0] = Math::RealEqual(dot[0], 0.0f, 1e-3);
294
295
296        v1 = c - b;
297        v2 = p - b;
298
299                dot[1] = v1.crossProduct(v2).dotProduct(normal);
300                zeroDot[1] = Math::RealEqual(dot[1], 0.0f, 1e-3);
301
302                // Compare signs (ignore colinear / coincident points)
303                if(!zeroDot[0] && !zeroDot[1] 
304                        && Math::Sign(dot[0]) != Math::Sign(dot[1]))
305                {
306            return false;
307                }
308
309        v1 = a - c;
310        v2 = p - c;
311
312                dot[2] = v1.crossProduct(v2).dotProduct(normal);
313                zeroDot[2] = Math::RealEqual(dot[2], 0.0f, 1e-3);
314                // Compare signs (ignore colinear / coincident points)
315                if((!zeroDot[0] && !zeroDot[2] 
316                        && Math::Sign(dot[0]) != Math::Sign(dot[2])) ||
317                        (!zeroDot[1] && !zeroDot[2] 
318                        && Math::Sign(dot[1]) != Math::Sign(dot[2])))
319                {
320                        return false;
321                }
322
323
324        return true;
325        }
326    //-----------------------------------------------------------------------
327    bool Math::RealEqual( Real a, Real b, Real tolerance )
328    {
329        if (fabs(b-a) <= tolerance)
330            return true;
331        else
332            return false;
333    }
334    //-----------------------------------------------------------------------
335    Vector3 Math::calculateTangentSpaceVector(
336        const Vector3& position1, const Vector3& position2, const Vector3& position3,
337        Real u1, Real v1, Real u2, Real v2, Real u3, Real v3)
338    {
339            //side0 is the vector along one side of the triangle of vertices passed in,
340            //and side1 is the vector along another side. Taking the cross product of these returns the normal.
341            Vector3 side0 = position1 - position2;
342            Vector3 side1 = position3 - position1;
343            //Calculate face normal
344            Vector3 normal = side1.crossProduct(side0);
345            normal.normalise();
346            //Now we use a formula to calculate the tangent.
347            Real deltaV0 = v1 - v2;
348            Real deltaV1 = v3 - v1;
349            Vector3 tangent = deltaV1 * side0 - deltaV0 * side1;
350            tangent.normalise();
351            //Calculate binormal
352            Real deltaU0 = u1 - u2;
353            Real deltaU1 = u3 - u1;
354            Vector3 binormal = deltaU1 * side0 - deltaU0 * side1;
355            binormal.normalise();
356            //Now, we take the cross product of the tangents to get a vector which
357            //should point in the same direction as our normal calculated above.
358            //If it points in the opposite direction (the dot product between the normals is less than zero),
359            //then we need to reverse the s and t tangents.
360            //This is because the triangle has been mirrored when going from tangent space to object space.
361            //reverse tangents if necessary
362            Vector3 tangentCross = tangent.crossProduct(binormal);
363            if (tangentCross.dotProduct(normal) < 0.0f)
364            {
365                    tangent = -tangent;
366                    binormal = -binormal;
367            }
368
369        return tangent;
370
371    }
372    //-----------------------------------------------------------------------
373    Vector4 Math::calculateFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3)
374    {
375        Vector3 normal = calculateBasicFaceNormal(v1, v2, v3);
376        // Now set up the w (distance of tri from origin
377        return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1)));
378    }
379    //-----------------------------------------------------------------------
380    Vector3 Math::calculateBasicFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3)
381    {
382        Vector3 normal = (v2 - v1).crossProduct(v3 - v1);
383        normal.normalise();
384        return normal;
385    }
386    //-----------------------------------------------------------------------
387    Vector4 Math::calculateFaceNormalWithoutNormalize(const Vector3& v1, const Vector3& v2, const Vector3& v3)
388    {
389        Vector3 normal = calculateBasicFaceNormalWithoutNormalize(v1, v2, v3);
390        // Now set up the w (distance of tri from origin)
391        return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1)));
392    }
393    //-----------------------------------------------------------------------
394    Vector3 Math::calculateBasicFaceNormalWithoutNormalize(const Vector3& v1, const Vector3& v2, const Vector3& v3)
395    {
396        Vector3 normal = (v2 - v1).crossProduct(v3 - v1);
397        return normal;
398    }
399        //-----------------------------------------------------------------------
400        Real Math::gaussianDistribution(Real x, Real offset, Real scale)
401        {
402                Real nom = Math::Exp(
403                        -Math::Sqr(x - offset) / (2 * Math::Sqr(scale)));
404                Real denom = scale * Math::Sqrt(2 * Math::PI);
405
406                return nom / denom;
407
408        }
409        //---------------------------------------------------------------------
410        Matrix4 Math::makeViewMatrix(const Vector3& position, const Quaternion& orientation, 
411                const Matrix4* reflectMatrix)
412        {
413                Matrix4 viewMatrix;
414
415                // View matrix is:
416                //
417                //  [ Lx  Uy  Dz  Tx  ]
418                //  [ Lx  Uy  Dz  Ty  ]
419                //  [ Lx  Uy  Dz  Tz  ]
420                //  [ 0   0   0   1   ]
421                //
422                // Where T = -(Transposed(Rot) * Pos)
423
424                // This is most efficiently done using 3x3 Matrices
425                Matrix3 rot;
426                orientation.ToRotationMatrix(rot);
427
428                // Make the translation relative to new axes
429                Matrix3 rotT = rot.Transpose();
430                Vector3 trans = -rotT * position;
431
432                // Make final matrix
433                viewMatrix = Matrix4::IDENTITY;
434                viewMatrix = rotT; // fills upper 3x3
435                viewMatrix[0][3] = trans.x;
436                viewMatrix[1][3] = trans.y;
437                viewMatrix[2][3] = trans.z;
438
439                // Deal with reflections
440                if (reflectMatrix)
441                {
442                        viewMatrix = viewMatrix * (*reflectMatrix);
443                }
444
445                return viewMatrix;
446
447        }
448
449}
Note: See TracBrowser for help on using the repository browser.