source: trunk/src/matrix.cpp @ 1046

Last change on this file since 1046 was 1046, checked in by sam, 12 years ago

core: split vector operations into linear and non-linear so that we can
reuse the linear operations in quaternions. Also mark some constructors
explicit to better spot coding errors.

  • Property svn:keywords set to Id
File size: 8.3 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#if defined WIN32 && !defined _XBOX
16#   define _USE_MATH_DEFINES /* for M_PI */
17#   define WIN32_LEAN_AND_MEAN
18#   include <windows.h>
19#   undef near /* Fuck Microsoft */
20#   undef far /* Fuck Microsoft again */
21#endif
22
23#include <cmath> /* for M_PI */
24#include <cstdlib> /* free() */
25#include <cstring> /* strdup() */
26
27#include "core.h"
28
29using namespace std;
30
31namespace lol
32{
33
34template<> float dot(vec2 v1, vec2 v2)
35{
36    return v1.x * v2.x + v1.y * v2.y;
37}
38
39template<> float dot(vec3 v1, vec3 v2)
40{
41    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
42}
43
44template<> float dot(vec4 v1, vec4 v2)
45{
46    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
47}
48
49template<> vec3 cross(vec3 v1, vec3 v2)
50{
51    return vec3(v1.y * v2.z - v1.z * v2.y,
52                v1.z * v2.x - v1.x * v2.z,
53                v1.x * v2.y - v1.y * v2.x);
54}
55
56template<> vec2 normalize(vec2 v)
57{
58    float norm = v.len();
59    if (!norm)
60        return vec2(0);
61    return v / norm;
62}
63
64template<> vec3 normalize(vec3 v)
65{
66    float norm = v.len();
67    if (!norm)
68        return vec3(0);
69    return v / norm;
70}
71
72template<> vec4 normalize(vec4 v)
73{
74    float norm = v.len();
75    if (!norm)
76        return vec4(0.0f);
77    return v / norm;
78}
79
80static inline float det3(float a, float b, float c,
81                         float d, float e, float f,
82                         float g, float h, float i)
83{
84    return a * (e * i - h * f)
85         + b * (f * g - i * d)
86         + c * (d * h - g * e);
87}
88
89static inline float cofact3(mat4 const &mat, int i, int j)
90{
91    return det3(mat[(i + 1) & 3][(j + 1) & 3],
92                mat[(i + 2) & 3][(j + 1) & 3],
93                mat[(i + 3) & 3][(j + 1) & 3],
94                mat[(i + 1) & 3][(j + 2) & 3],
95                mat[(i + 2) & 3][(j + 2) & 3],
96                mat[(i + 3) & 3][(j + 2) & 3],
97                mat[(i + 1) & 3][(j + 3) & 3],
98                mat[(i + 2) & 3][(j + 3) & 3],
99                mat[(i + 3) & 3][(j + 3) & 3]) * (((i + j) & 1) ? -1.0f : 1.0f);
100}
101
102template<> float mat4::det() const
103{
104    float ret = 0;
105    for (int n = 0; n < 4; n++)
106        ret += (*this)[n][0] * cofact3(*this, n, 0);
107    return ret;
108}
109
110template<> mat4 mat4::invert() const
111{
112    mat4 ret;
113    float d = det();
114    if (d)
115    {
116        d = 1.0f / d;
117        for (int j = 0; j < 4; j++)
118            for (int i = 0; i < 4; i++)
119                ret[j][i] = cofact3(*this, i, j) * d;
120    }
121    return ret;
122}
123
124template<> void vec2::printf() const
125{
126    Log::Debug("[ %6.6f %6.6f ]\n", x, y);
127}
128
129template<> void ivec2::printf() const
130{
131    Log::Debug("[ %i %i ]\n", x, y);
132}
133
134template<> void vec3::printf() const
135{
136    Log::Debug("[ %6.6f %6.6f %6.6f ]\n", x, y, z);
137}
138
139template<> void ivec3::printf() const
140{
141    Log::Debug("[ %i %i %i ]\n", x, y, z);
142}
143
144template<> void vec4::printf() const
145{
146    Log::Debug("[ %6.6f %6.6f %6.6f %6.6f ]\n", x, y, z, w);
147}
148
149template<> void ivec4::printf() const
150{
151    Log::Debug("[ %i %i %i %i ]\n", x, y, z, w);
152}
153
154template<> void mat4::printf() const
155{
156    mat4 const &p = *this;
157
158    Log::Debug("[ %6.6f %6.6f %6.6f %6.6f\n",
159               p[0][0], p[1][0], p[2][0], p[3][0]);
160    Log::Debug("  %6.6f %6.6f %6.6f %6.6f\n",
161               p[0][1], p[1][1], p[2][1], p[3][1]);
162    Log::Debug("  %6.6f %6.6f %6.6f %6.6f\n",
163               p[0][2], p[1][2], p[2][2], p[3][2]);
164    Log::Debug("  %6.6f %6.6f %6.6f %6.6f ]\n",
165               p[0][3], p[1][3], p[2][3], p[3][3]);
166}
167
168#if !defined __ANDROID__
169template<> std::ostream &operator<<(std::ostream &stream, ivec2 const &v)
170{
171    return stream << "(" << v.x << ", " << v.y << ")";
172}
173
174template<> std::ostream &operator<<(std::ostream &stream, ivec3 const &v)
175{
176    return stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
177}
178
179template<> std::ostream &operator<<(std::ostream &stream, ivec4 const &v)
180{
181    return stream << "(" << v.x << ", " << v.y << ", "
182                         << v.z << ", " << v.w << ")";
183}
184
185template<> std::ostream &operator<<(std::ostream &stream, vec2 const &v)
186{
187    return stream << "(" << v.x << ", " << v.y << ")";
188}
189
190template<> std::ostream &operator<<(std::ostream &stream, vec3 const &v)
191{
192    return stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
193}
194
195template<> std::ostream &operator<<(std::ostream &stream, vec4 const &v)
196{
197    return stream << "(" << v.x << ", " << v.y << ", "
198                         << v.z << ", " << v.w << ")";
199}
200
201template<> std::ostream &operator<<(std::ostream &stream, mat4 const &m)
202{
203    stream << "((" << m[0][0] << ", " << m[1][0]
204            << ", " << m[2][0] << ", " << m[3][0] << "), ";
205    stream << "(" << m[0][1] << ", " << m[1][1]
206           << ", " << m[2][1] << ", " << m[3][1] << "), ";
207    stream << "(" << m[0][2] << ", " << m[1][2]
208           << ", " << m[2][2] << ", " << m[3][2] << "), ";
209    stream << "(" << m[0][3] << ", " << m[1][3]
210           << ", " << m[2][3] << ", " << m[3][3] << "))";
211    return stream;
212}
213#endif
214
215template<> mat4 mat4::translate(float x, float y, float z)
216{
217    mat4 ret(1.0f);
218    ret[3][0] = x;
219    ret[3][1] = y;
220    ret[3][2] = z;
221    return ret;
222}
223
224template<> mat4 mat4::translate(vec3 v)
225{
226    return translate(v.x, v.y, v.z);
227}
228
229template<> mat4 mat4::rotate(float angle, float x, float y, float z)
230{
231    angle *= (M_PI / 180.0f);
232
233    float st = sinf(angle);
234    float ct = cosf(angle);
235
236    float len = sqrtf(x * x + y * y + z * z);
237    float invlen = len ? 1.0f / len : 0.0f;
238    x *= invlen;
239    y *= invlen;
240    z *= invlen;
241
242    float mtx = (1.0f - ct) * x;
243    float mty = (1.0f - ct) * y;
244    float mtz = (1.0f - ct) * z;
245
246    mat4 ret(1.0f);
247
248    ret[0][0] = x * mtx + ct;
249    ret[0][1] = x * mty + st * z;
250    ret[0][2] = x * mtz - st * y;
251
252    ret[1][0] = y * mtx - st * z;
253    ret[1][1] = y * mty + ct;
254    ret[1][2] = y * mtz + st * x;
255
256    ret[2][0] = z * mtx + st * y;
257    ret[2][1] = z * mty - st * x;
258    ret[2][2] = z * mtz + ct;
259
260    return ret;
261}
262
263template<> mat4 mat4::rotate(float angle, vec3 v)
264{
265    return rotate(angle, v.x, v.y, v.z);
266}
267
268template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up)
269{
270    vec3 v3 = normalize(eye - center);
271    vec3 v2 = normalize(up);
272    vec3 v1 = normalize(cross(v2, v3));
273    v2 = cross(v3, v1);
274
275    mat4 orient(1.0f);
276    orient[0][0] = v1.x;
277    orient[0][1] = v2.x;
278    orient[0][2] = v3.x;
279    orient[1][0] = v1.y;
280    orient[1][1] = v2.y;
281    orient[1][2] = v3.y;
282    orient[2][0] = v1.z;
283    orient[2][1] = v2.z;
284    orient[2][2] = v3.z;
285
286    return orient * mat4::translate(-eye);
287}
288
289template<> mat4 mat4::ortho(float left, float right, float bottom,
290                            float top, float near, float far)
291{
292    float invrl = (right != left) ? 1.0f / (right - left) : 0.0f;
293    float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f;
294    float invfn = (far != near) ? 1.0f / (far - near) : 0.0f;
295
296    mat4 ret(0.0f);
297    ret[0][0] = 2.0f * invrl;
298    ret[1][1] = 2.0f * invtb;
299    ret[2][2] = -2.0f * invfn;
300    ret[3][0] = - (right + left) * invrl;
301    ret[3][1] = - (top + bottom) * invtb;
302    ret[3][2] = - (far + near) * invfn;
303    ret[3][3] = 1.0f;
304    return ret;
305}
306
307template<> mat4 mat4::frustum(float left, float right, float bottom,
308                              float top, float near, float far)
309{
310    float invrl = (right != left) ? 1.0f / (right - left) : 0.0f;
311    float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f;
312    float invfn = (far != near) ? 1.0f / (far - near) : 0.0f;
313
314    mat4 ret(0.0f);
315    ret[0][0] = 2.0f * near * invrl;
316    ret[1][1] = 2.0f * near * invtb;
317    ret[2][0] = (right + left) * invrl;
318    ret[2][1] = (top + bottom) * invtb;
319    ret[2][2] = - (far + near) * invfn;
320    ret[2][3] = -1.0f;
321    ret[3][2] = -2.0f * far * near * invfn;
322    return ret;
323}
324
325template<> mat4 mat4::perspective(float fov_y, float width,
326                                  float height, float near, float far)
327{
328    fov_y *= (M_PI / 180.0f);
329
330    float t2 = tanf(fov_y * 0.5f);
331    float t1 = t2 * width / height;
332
333    return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far);
334}
335
336} /* namespace lol */
337
Note: See TracBrowser for help on using the repository browser.