Browse Source

Added Quaternion into utils.

Used equalEpsilon in Sound to silence warning
Thomas Buck 11 years ago
parent
commit
d813f77f4e
4 changed files with 495 additions and 1 deletions
  1. 201
    0
      include/utils/Quaternion.h
  2. 2
    1
      src/Sound.cpp
  3. 3
    0
      src/utils/CMakeLists.txt
  4. 289
    0
      src/utils/Quaternion.cpp

+ 201
- 0
include/utils/Quaternion.h View File

@@ -0,0 +1,201 @@
1
+/*!
2
+ * \file include/utils/Quaternion.h
3
+ * \brief Quaternion
4
+ *
5
+ * \author Mongoose
6
+ */
7
+
8
+#ifndef _UTILS_QUATERNION_H_
9
+#define _UTILS_QUATERNION_H_
10
+
11
+#include "utils/math.h"
12
+
13
+/*!
14
+ * \brief Quaternion
15
+ */
16
+class Quaternion {
17
+public:
18
+
19
+    /*!
20
+     * \brief Constructs an object of Quaternion
21
+     */
22
+    Quaternion();
23
+
24
+    /*!
25
+     * \brief Constructs an object of Quaternion
26
+     * \param w W part of new Quaternion
27
+     * \param x X part of new Quaternion
28
+     * \param y Y part of new Quaternion
29
+     * \param z Z part of new Quaternion
30
+     */
31
+    Quaternion(vec_t w, vec_t x, vec_t y, vec_t z);
32
+
33
+    /*!
34
+     * \brief Constructs an object of Quaternion
35
+     * \param v contents of new Quaternion
36
+     */
37
+    Quaternion(vec4_t v);
38
+
39
+    /*!
40
+     * \brief Get column order matrix equivalent of this quaternion
41
+     * \param m where matrix will be stored
42
+     */
43
+    void getMatrix(matrix_t m);
44
+
45
+    /*!
46
+     * \brief Multiplies this quaternion.
47
+     *
48
+     * Use normalize() call for unit quaternion.
49
+     *
50
+     * \param q what to multiply this quaternion with
51
+     * \returns resultant quaternion
52
+     * \sa Quaternion::normalize()
53
+     */
54
+    Quaternion operator *(const Quaternion &q);
55
+
56
+    /*!
57
+     * \brief Divide from this quaternion
58
+     * \param q what to divide from this quaternion
59
+     * \returns resultant quaternion
60
+     */
61
+    Quaternion operator /(const Quaternion &q);
62
+
63
+    /*!
64
+     * \brief Add to this quaternion
65
+     * \param q what to add to this quaternion
66
+     * \returns resultant quaternion
67
+     */
68
+    Quaternion operator +(const Quaternion &q);
69
+
70
+    /*!
71
+     * \brief Subtract from this quaternion
72
+     * \param q what to subtract from this quaternion
73
+     * \returns resultant quaternion
74
+     */
75
+    Quaternion operator -(const Quaternion &q);
76
+
77
+    /*!
78
+     * \brief Compares q to this quaternion
79
+     * \param q what to compare this quaternion to
80
+     * \returns true if equal, false otherwise
81
+     */
82
+    bool operator ==(const Quaternion &q);
83
+
84
+    /*!
85
+     * \brief Conjugate this quaternion
86
+     * \returns Conjugate of this quaternion
87
+     */
88
+    Quaternion conjugate();
89
+
90
+    /*!
91
+     * \brief Scale this quaternion
92
+     * \param s scaling factor
93
+     * \returns Scaled result of this quaternion
94
+     */
95
+    Quaternion scale(vec_t s);
96
+
97
+    /*!
98
+     * \brief Inverse this quaternion
99
+     * \returns inverse of this quaternion
100
+     */
101
+    Quaternion inverse();
102
+
103
+    /*!
104
+     * \brief Dot Product of quaternions
105
+     * \param a first argument to dot product
106
+     * \param b second argument to dot product
107
+     * \returns dot product between a and b quaternions
108
+     */
109
+    static vec_t dot(Quaternion a, Quaternion b);
110
+
111
+    /*!
112
+     * \brief Magnitude of this quaternion
113
+     * \returns Magnitude of this quaternion
114
+     */
115
+    vec_t magnitude();
116
+
117
+    /*!
118
+     * \brief Interpolates between a and b rotations.
119
+     *
120
+     * Using spherical linear interpolation:
121
+     * `I = (((B . A)^-1)^Time)A`
122
+     *
123
+     * \param a first argument for slerp
124
+     * \param b second argument for slerp
125
+     * \param time time argument for slerp
126
+     * \returns resultant quaternion
127
+     */
128
+    static Quaternion slerp(Quaternion a, Quaternion b, vec_t time);
129
+
130
+    /*!
131
+     * \brief Sets this quaternion to identity
132
+     */
133
+    void setIdentity();
134
+
135
+    /*!
136
+     * \brief Sets this quaternion
137
+     * \param angle new angle
138
+     * \param x new X coordinate
139
+     * \param y new Y coordinate
140
+     * \param z new Z coordinate
141
+     */
142
+    void set(vec_t angle, vec_t x, vec_t y, vec_t z);
143
+
144
+    /*!
145
+     * \brief Normalize this quaternion
146
+     */
147
+    void normalize();
148
+
149
+    /*!
150
+     * \brief Set this quaternion
151
+     * \param q will be copied into this quaternion
152
+     */
153
+    void copy(Quaternion q);
154
+
155
+    /*!
156
+     * \brief Sets matrix equivalent of this quaternion
157
+     * \param m matrix in valid column order
158
+     */
159
+    void setByMatrix(matrix_t m);
160
+
161
+private:
162
+
163
+    /*!
164
+     * \brief Multiplies two quaternions
165
+     * \param a first argument to multiplication
166
+     * \param b second argument to multiplication
167
+     * \returns resultant quaternion
168
+     */
169
+    static Quaternion multiply(Quaternion a, Quaternion b);
170
+
171
+    /*!
172
+     * \brief Divides B from A quaternion
173
+     * \param a first argument to division
174
+     * \param b second argument to division
175
+     * \returns quotient quaternion
176
+     */
177
+    static Quaternion divide(Quaternion a, Quaternion b);
178
+
179
+    /*!
180
+     * \brief Adds A and B quaternions
181
+     * \param a first argument to addition
182
+     * \param b second argument to addition
183
+     * \returns resultant quaternion
184
+     */
185
+    static Quaternion add(Quaternion a, Quaternion b);
186
+
187
+    /*!
188
+     * \brief Subtracts B from A quaternion
189
+     * \param a first argument to subtraction
190
+     * \param b second argument to subtraction
191
+     * \returns resultant quaternion
192
+     */
193
+    static Quaternion subtract(Quaternion a, Quaternion b);
194
+
195
+    vec_t mW; //!< Quaternion, W part
196
+    vec_t mX; //!< Quaternion, X part
197
+    vec_t mY; //!< Quaternion, Y part
198
+    vec_t mZ; //!< Quaternion, Z part
199
+};
200
+
201
+#endif

+ 2
- 1
src/Sound.cpp View File

@@ -24,6 +24,7 @@
24 24
 #include <unistd.h>
25 25
 #include <assert.h>
26 26
 
27
+#include "utils/math.h"
27 28
 #include "Sound.h"
28 29
 
29 30
 Sound::Sound() {
@@ -91,7 +92,7 @@ void Sound::setVolume(float vol) {
91 92
     assert(mInit == true);
92 93
     assert(mSource.size() == mBuffer.size());
93 94
 
94
-    if ((mSource.size() > 0) && (mVolume != vol)) {
95
+    if ((mSource.size() > 0) && (!equalEpsilon(mVolume, vol))) {
95 96
         // Apply new volume to old sources if needed
96 97
         for (size_t i = 0; i < mSource.size(); i++)
97 98
             alSourcef(mSource[i], AL_GAIN, vol);

+ 3
- 0
src/utils/CMakeLists.txt View File

@@ -1,8 +1,11 @@
1 1
 # Source files
2 2
 set (UTIL_SRCS ${UTIL_SRCS} "math.cpp")
3
+set (UTIL_SRCS ${UTIL_SRCS} "Matrix.cpp")
4
+set (UTIL_SRCS ${UTIL_SRCS} "Quaternion.cpp")
3 5
 set (UTIL_SRCS ${UTIL_SRCS} "strings.cpp")
4 6
 set (UTIL_SRCS ${UTIL_SRCS} "tga.cpp")
5 7
 set (UTIL_SRCS ${UTIL_SRCS} "time.cpp")
8
+set (UTIL_SRCS ${UTIL_SRCS} "Vector3d.cpp")
6 9
 
7 10
 # Include directory
8 11
 include_directories ("${PROJECT_SOURCE_DIR}/include")

+ 289
- 0
src/utils/Quaternion.cpp View File

@@ -0,0 +1,289 @@
1
+/*!
2
+ * \file src/utils/Quaternion.cpp
3
+ * \brief Quaternion
4
+ *
5
+ * \author Mongoose
6
+ */
7
+
8
+#include <math.h>
9
+
10
+#include "utils/Quaternion.h"
11
+
12
+Quaternion::Quaternion() {
13
+    mW = 0;
14
+    mX = 0;
15
+    mY = 0;
16
+    mZ = 0;
17
+}
18
+
19
+Quaternion::Quaternion(vec_t w, vec_t x, vec_t y, vec_t z) {
20
+    mW = w;
21
+    mX = x;
22
+    mY = y;
23
+    mZ = z;
24
+}
25
+
26
+Quaternion::Quaternion(vec4_t v) {
27
+    mW = v[0];
28
+    mX = v[1];
29
+    mY = v[2];
30
+    mZ = v[3];
31
+}
32
+
33
+void Quaternion::getMatrix(matrix_t m) {
34
+    m[ 0] = 1.0f - 2.0f * (mY*mY + mZ*mZ);
35
+    m[ 1] = 2.0f * (mX*mY - mW*mZ);
36
+    m[ 2] = 2.0f * (mX*mZ + mW*mY);
37
+    m[ 3] = 0.0f;
38
+
39
+    m[ 4] = 2.0f * (mX*mY + mW*mZ);
40
+    m[ 5] = 1.0f - 2.0f * (mX*mX + mZ*mZ);
41
+    m[ 6] = 2.0f * (mY*mZ - mW*mX);
42
+    m[ 7] = 0.0f;
43
+
44
+    m[ 8] = 2.0f * (mX*mZ - mW*mY);
45
+    m[ 9] = 2.0f * (mY*mZ + mW*mX);
46
+    m[10] = 1.0f - 2.0f * (mX*mX + mY*mY);
47
+    m[11] = 0.0f;
48
+
49
+    m[12] = 0.0f;
50
+    m[13] = 0.0f;
51
+    m[14] = 0.0f;
52
+    m[15] = 1.0f;
53
+}
54
+
55
+Quaternion Quaternion::operator *(const Quaternion &q) {
56
+    return multiply(*this, q);
57
+}
58
+
59
+Quaternion Quaternion::operator /(const Quaternion &q) {
60
+    return divide(*this, q);
61
+}
62
+
63
+Quaternion Quaternion::operator +(const Quaternion &q) {
64
+    return add(*this, q);
65
+}
66
+
67
+Quaternion Quaternion::operator -(const Quaternion &q) {
68
+    return subtract(*this, q);
69
+}
70
+
71
+bool Quaternion::operator ==(const Quaternion &q) {
72
+    //return (mX == q.mX && mY == q.mY && mZ == q.mZ && mW == q.mW);
73
+    return (equalEpsilon(mX, q.mX) && equalEpsilon(mY, q.mY) &&
74
+            equalEpsilon(mZ, q.mZ) && equalEpsilon(mW, q.mW));
75
+}
76
+
77
+Quaternion Quaternion::conjugate() {
78
+    return Quaternion(mW, -mX, -mY, -mZ);
79
+}
80
+
81
+Quaternion Quaternion::scale(vec_t s) {
82
+    return Quaternion(mW * s, mX * s, mY * s, mZ * s);
83
+}
84
+
85
+Quaternion Quaternion::inverse() {
86
+    return conjugate().scale(1/magnitude());
87
+}
88
+
89
+vec_t Quaternion::dot(Quaternion a, Quaternion b) {
90
+    return ((a.mW * b.mW) + (a.mX * b.mX) + (a.mY * b.mY) + (a.mZ * b.mZ));
91
+}
92
+
93
+vec_t Quaternion::magnitude() {
94
+    return sqrtf(dot(*this, *this));
95
+}
96
+
97
+void Quaternion::setIdentity() {
98
+    mW = 1.0;
99
+    mX = 0.0;
100
+    mY = 0.0;
101
+    mZ = 0.0;
102
+}
103
+
104
+void Quaternion::set(vec_t angle, vec_t x, vec_t y, vec_t z) {
105
+    vec_t temp, dist;
106
+
107
+    // Normalize
108
+    temp = x*x + y*y + z*z;
109
+
110
+    dist = 1.0f / sqrtf(temp);
111
+
112
+    x *= dist;
113
+    y *= dist;
114
+    z *= dist;
115
+
116
+    mX = x;
117
+    mY = y;
118
+    mZ = z;
119
+
120
+    mW = cosf(angle / 2.0f);
121
+}
122
+
123
+void Quaternion::normalize() {
124
+    vec_t dist, square;
125
+
126
+    square = mX * mX + mY * mY + mZ * mZ + mW * mW;
127
+
128
+    if (square > 0.0) {
129
+        dist = 1.0f / sqrtf(square);
130
+    } else {
131
+        dist = 1;
132
+    }
133
+
134
+    mX *= dist;
135
+    mY *= dist;
136
+    mZ *= dist;
137
+    mW *= dist;
138
+}
139
+
140
+void Quaternion::copy(Quaternion q) {
141
+    mW = q.mW;
142
+    mX = q.mX;
143
+    mY = q.mY;
144
+    mZ = q.mZ;
145
+}
146
+
147
+Quaternion Quaternion::slerp(Quaternion a, Quaternion b, vec_t time) {
148
+    /*******************************************************************
149
+     * Spherical Linear Interpolation algorthim
150
+     *-----------------------------------------------------------------
151
+     *
152
+     * Interpolate between A and B rotations ( Find qI )
153
+     *
154
+     * qI = (((qB . qA)^ -1)^ Time) qA
155
+     *
156
+     * http://www.magic-software.com/Documentation/quat.pdf
157
+     *
158
+     * Thanks to digiben for algorithms and basis of the notes in
159
+     * this func
160
+     *
161
+     *******************************************************************/
162
+
163
+    vec_t result, scaleA, scaleB;
164
+    Quaternion i;
165
+
166
+
167
+    // Don't bother if it's the same rotation, it's the same as the result
168
+    if (a == b)
169
+        return a;
170
+
171
+    // A . B
172
+    result = dot(a, b);
173
+
174
+    // If the dot product is less than 0, the angle is greater than 90 degrees
175
+    if (result < 0.0f) {
176
+        // Negate quaternion B and the result of the dot product
177
+        b = Quaternion(-b.mW, -b.mX, -b.mY, -b.mZ);
178
+        result = -result;
179
+    }
180
+
181
+    // Set the first and second scale for the interpolation
182
+    scaleA = 1 - time;
183
+    scaleB = time;
184
+
185
+    // Next, we want to actually calculate the spherical interpolation.  Since this
186
+    // calculation is quite computationally expensive, we want to only perform it
187
+    // if the angle between the 2 quaternions is large enough to warrant it.  If the
188
+    // angle is fairly small, we can actually just do a simpler linear interpolation
189
+    // of the 2 quaternions, and skip all the complex math.  We create a "delta" value
190
+    // of 0.1 to say that if the cosine of the angle (result of the dot product) between
191
+    // the 2 quaternions is smaller than 0.1, then we do NOT want to perform the full on
192
+    // interpolation using.  This is because you won't really notice the difference.
193
+
194
+    // Check if the angle between the 2 quaternions was big enough
195
+    // to warrant such calculations
196
+    if (1 - result > 0.1f) {
197
+        // Get the angle between the 2 quaternions, and then
198
+        // store the sin() of that angle
199
+        vec_t theta = (float)acos(result);
200
+        vec_t sinTheta = (float)sin(theta);
201
+
202
+        // Calculate the scale for qA and qB, according to
203
+        // the angle and it's sine value
204
+        scaleA = (float)sin((1 - time) * theta) / sinTheta;
205
+        scaleB = (float)sin((time * theta)) / sinTheta;
206
+    }
207
+
208
+    // Calculate the x, y, z and w values for the quaternion by using a special
209
+    // form of linear interpolation for quaternions.
210
+    return (a.scale(scaleA) + b.scale(scaleB));
211
+}
212
+
213
+void Quaternion::setByMatrix(matrix_t matrix) {
214
+    float diagonal = matrix[0] + matrix[5] + matrix[10] + 1.0f;
215
+    float scale = 0.0f;
216
+    float w = 0.0f, x = 0.0f, y = 0.0f, z = 0.0f;
217
+
218
+    if (diagonal > 0.00000001) {
219
+        // Calculate the scale of the diagonal
220
+        scale = (float)(sqrt(diagonal) * 2);
221
+
222
+        w = 0.25f * scale;
223
+        x = (matrix[9] - matrix[6]) / scale;
224
+        y = (matrix[2] - matrix[8]) / scale;
225
+        z = (matrix[4] - matrix[1]) / scale;
226
+    } else {
227
+        // If the first element of the diagonal is the greatest value
228
+        if (matrix[0] > matrix[5] && matrix[0] > matrix[10]) {
229
+            // Find the scale according to the first element, and double it
230
+            scale = (float)sqrt(1.0f + matrix[0] - matrix[5] - matrix[10])*2.0f;
231
+
232
+            // Calculate the quaternion
233
+            w = (matrix[9] - matrix[6]) / scale;
234
+            x = 0.25f * scale;
235
+            y = (matrix[4] + matrix[1]) / scale;
236
+            z = (matrix[2] + matrix[8]) / scale;
237
+        } else if (matrix[5] > matrix[10]) {
238
+            // The second element of the diagonal is the greatest value
239
+            // Find the scale according to the second element, and double it
240
+            scale = (float)sqrt(1.0f + matrix[5] - matrix[0] - matrix[10])*2.0f;
241
+
242
+            // Calculate the quaternion
243
+            w = (matrix[2] - matrix[8]) / scale;
244
+            x = (matrix[4] + matrix[1]) / scale;
245
+            y = 0.25f * scale;
246
+            z = (matrix[9] + matrix[6]) / scale;
247
+        } else { // The third element of the diagonal is the greatest value
248
+            // Find the scale according to the third element, and double it
249
+            scale = (float)sqrt(1.0f + matrix[10] - matrix[0] - matrix[5])*2.0f;
250
+
251
+            // Calculate the quaternion
252
+            w = (matrix[4] - matrix[1]) / scale;
253
+            x = (matrix[2] + matrix[8]) / scale;
254
+            y = (matrix[9] + matrix[6]) / scale;
255
+            z = 0.25f * scale;
256
+        }
257
+    }
258
+
259
+    mW = w;
260
+    mX = x;
261
+    mY = y;
262
+    mZ = z;
263
+}
264
+
265
+Quaternion Quaternion::multiply(Quaternion a, Quaternion b) {
266
+    return Quaternion(a.mW * b.mW - a.mX * b.mX - a.mY * b.mY - a.mZ * b.mZ,
267
+            a.mW * b.mX + a.mX * b.mW + a.mY * b.mZ - a.mZ * b.mY,
268
+            a.mW * b.mY + a.mY * b.mW + a.mZ * b.mX - a.mX * b.mZ,
269
+            a.mW * b.mZ + a.mZ * b.mW + a.mX * b.mY - a.mY * b.mX);
270
+}
271
+
272
+Quaternion Quaternion::divide(Quaternion a, Quaternion b) {
273
+    return (a * (b.inverse()));
274
+}
275
+
276
+Quaternion Quaternion::add(Quaternion a, Quaternion b) {
277
+    return Quaternion(a.mW + b.mW,
278
+            a.mX + b.mX,
279
+            a.mY + b.mY,
280
+            a.mZ + b.mZ);
281
+}
282
+
283
+Quaternion Quaternion::subtract(Quaternion a, Quaternion b) {
284
+    return Quaternion(a.mW - b.mW,
285
+            a.mX - b.mX,
286
+            a.mY - b.mY,
287
+            a.mZ - b.mZ);
288
+}
289
+

Loading…
Cancel
Save