3 This file is part of libmspgl
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
10 #include <msp/core/except.h>
21 for(unsigned i=0; i<16; ++i)
22 matrix[i] = (i%5 ? 0 : 1);
25 Matrix::Matrix(const float *m):
28 copy(m, m+16, matrix);
32 Matrix::Matrix(const double *m):
35 copy(m, m+16, matrix);
39 void Matrix::check_flags()
41 const double *m = matrix;
42 if(m[12]!=0 || m[13]!=0 || m[14]!=0)
47 if(m[5]!=m[0] || m[10]!=m[0])
50 if(m[1]!=0 || m[2]!=0 || m[4]!=0 || m[6]!=0 || m[8]!=0 || m[9]!=0)
53 double x_dot_y = m[0]*m[1]+m[4]*m[5]+m[8]*m[9];
54 double x_dot_z = m[0]*m[2]+m[4]*m[6]+m[8]*m[10];
55 double y_dot_z = m[1]*m[2]+m[5]*m[6]+m[9]*m[10];
56 if(x_dot_y!=0 || x_dot_z!=0 || y_dot_z!=0)
59 if(m[3]!=0 || m[7]!=0 || m[11]!=0 || m[15]!=1)
63 void Matrix::multiply(const Matrix &other)
68 void Matrix::translate(double x, double y, double z)
70 multiply(translation(x, y, z));
73 void Matrix::rotate(double a, double x, double y, double z)
75 multiply(rotation(a, x, y, z));
78 void Matrix::rotate_deg(double a, double x, double y, double z)
80 multiply(rotation_deg(a, x, y, z));
83 void Matrix::scale(double s)
88 void Matrix::scale(double x, double y, double z)
90 multiply(scaling(x, y, z));
93 Matrix Matrix::operator*(const Matrix &other) const
97 else if(other.flags==IDENTITY)
99 else if(flags==TRANSLATE && !(other.flags&ARBITARY))
101 Matrix result = other;
102 result.matrix[12] += matrix[12];
103 result.matrix[13] += matrix[13];
104 result.matrix[14] += matrix[14];
105 result.flags |= flags;
108 else if(!(flags&ARBITARY) && other.flags==TRANSLATE)
110 Matrix result = *this;
111 const double *m = other.matrix;
112 result.matrix[12] += matrix[0]*m[12]+matrix[4]*m[13]+matrix[8]*m[14];
113 result.matrix[13] += matrix[1]*m[12]+matrix[5]*m[13]+matrix[9]*m[14];
114 result.matrix[14] += matrix[2]*m[12]+matrix[6]*m[13]+matrix[10]*m[14];
115 result.flags |= other.flags;
121 fill(result.matrix, result.matrix+16, 0.0);
122 for(unsigned i=0; i<4; ++i)
123 for(unsigned j=0; j<4; ++j)
124 for(unsigned k=0; k<4; ++k)
125 result.matrix[i+j*4] += matrix[i+k*4]*other.matrix[k+j*4];
126 result.flags = flags|other.flags;
131 Matrix &Matrix::operator*=(const Matrix &other)
137 double Matrix::operator[](unsigned i) const
140 throw InvalidParameterValue("Matrix element index out of range");
144 Matrix Matrix::translation(double x, double y, double z)
147 result.matrix[12] = x;
148 result.matrix[13] = y;
149 result.matrix[14] = z;
150 result.flags |= TRANSLATE;
154 Matrix Matrix::rotation(double a, double x, double y, double z)
156 double l = sqrt(x*x+y*y+z*z);
163 // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_given_an_axis_and_an_angle
165 result.matrix[0] = c+x*x*(1-c);
166 result.matrix[1] = y*x*(1-c)+z*s;
167 result.matrix[2] = z*x*(1-c)-y*s;
168 result.matrix[4] = x*y*(1-c)-z*s;
169 result.matrix[5] = c+y*y*(1-c);
170 result.matrix[6] = z*y*(1-c)+x*s;
171 result.matrix[8] = x*z*(1-c)+y*s;
172 result.matrix[9] = y*z*(1-c)-x*s;
173 result.matrix[10] = c+z*z*(1-c);
174 result.flags |= ROTATE;
178 Matrix Matrix::rotation_deg(double a, double x, double y, double z)
180 return rotation(a*M_PI/180, x, y, z);
183 Matrix Matrix::scaling(double s)
186 result.matrix[0] = s;
187 result.matrix[5] = s;
188 result.matrix[10] = s;
189 result.flags |= SCALE;
193 Matrix Matrix::scaling(double x, double y, double z)
196 result.matrix[0] = x;
197 result.matrix[5] = y;
198 result.matrix[10] = z;
199 result.flags |= SCALE|ARBITARY;
203 Matrix Matrix::ortho(double l, double r, double b, double t, double n, double f)
205 if(l==r || b==t || n==f)
206 throw InvalidParameterValue("Orthogonal projection can't have zero dimension");
209 result.matrix[0] = 2/(r-l);
210 result.matrix[5] = 2/(t-b);
211 result.matrix[10] = -2/(f-n);
212 result.matrix[12] = -(r+l)/(r-l);
213 result.matrix[13] = -(t+b)/(t-b);
214 result.matrix[14] = -(f+n)/(f-n);
215 result.flags = TRANSLATE|SCALE|ARBITARY;
219 Matrix Matrix::ortho_centered(double w, double h)
221 return ortho(-w/2, w/2, -h/2, h/2, -1, 1);
224 Matrix Matrix::ortho_bottomleft(double w, double h)
226 return ortho(0, w, 0, h, -1, 1);
229 Matrix Matrix::ortho_topleft(double w, double h)
231 return ortho(0, w, h, 0, -1, 1);
234 Matrix Matrix::frustum(double l, double r, double b, double t, double n, double f)
236 if(l==r || b==t || n<=0 || f<=n)
237 throw InvalidParameterValue("Invalid frustum parameters");
240 result.matrix[0] = 2*n/(r-l);
241 result.matrix[5] = 2*n/(t-b);
242 result.matrix[8] = (r+l)/(r-l);
243 result.matrix[9] = (t+b)/(t-b);
244 result.matrix[10] = -(f+n)/(f-n);
245 result.matrix[11] = -1;
246 result.matrix[14] = -2*f*n/(f-n);
247 result.matrix[15] = 0;
248 result.flags = ARBITARY;
252 Matrix Matrix::frustum_centered(double w, double h, double n, double f)
254 return frustum(-w/2, w/2, -h/2, h/2, n, f);
257 Matrix Matrix::perspective(double h, double a, double n, double f)
259 double hh = tan(h/2)*n;
260 return frustum(-hh*a, hh*a, -hh, hh, n, f);
264 GLenum MatrixStack::current_mode = GL_MODELVIEW;
266 MatrixStack::MatrixStack(GLenum m):
269 matrices.push_back(Matrix());
272 MatrixStack::MatrixStack():
275 matrices.push_back(Matrix());
278 const Matrix &MatrixStack::top()
280 return matrices.back();
283 void MatrixStack::load(const Matrix &m)
289 void MatrixStack::multiply(const Matrix &m)
291 matrices.back() *= m;
295 void MatrixStack::push()
297 matrices.push_back(top());
300 void MatrixStack::pop()
302 if(matrices.size()==1)
303 throw InvalidState("Can't pop the last matrix");
309 void MatrixStack::update()
314 if(mode!=current_mode)
320 glLoadMatrixd(matrices.back().data());
323 MatrixStack &MatrixStack::operator=(const Matrix &m)
329 MatrixStack &MatrixStack::operator*=(const Matrix &m)
335 MatrixStack &MatrixStack::modelview()
337 static MatrixStack ms(GL_MODELVIEW);
341 MatrixStack &MatrixStack::projection()
343 static MatrixStack ms(GL_PROJECTION);
350 MatrixStack *active_stack = &MatrixStack::modelview();
352 void matrix_mode(MatrixMode m)
355 active_stack = &MatrixStack::modelview();
356 else if(m==PROJECTION)
357 active_stack = &MatrixStack::projection();
359 throw InvalidParameterValue("Texture matrices are not supported");
364 *active_stack = Matrix();
367 void load_matrix(const float *matrix)
369 *active_stack = Matrix(matrix);
372 void load_matrix(const double *matrix)
374 *active_stack = Matrix(matrix);
377 void mult_matrix(const float *matrix)
379 *active_stack *= Matrix(matrix);
382 void mult_matrix(const double *matrix)
384 *active_stack *= Matrix(matrix);
389 active_stack->push();
397 void translate(float x, float y, float z)
399 *active_stack *= Matrix::translation(x, y, z);
402 void rotate(float a, float x, float y, float z)
404 *active_stack *= Matrix::rotation_deg(a, x, y, z);
407 void scale(float x, float y, float z)
409 *active_stack *= Matrix::scaling(x, y, z);
412 void scale_uniform(float s)
414 *active_stack *= Matrix::scaling(s);