-/* $Id$
-
-This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
#include <algorithm>
#include <cmath>
-#include <msp/core/except.h>
+#include <msp/geometry/affinetransformation.h>
+#include <msp/gl/extensions/msp_legacy_features.h>
+#include "error.h"
#include "matrix.h"
using namespace std;
namespace GL {
Matrix::Matrix():
- flags(IDENTITY)
-{
- for(unsigned i=0; i<16; ++i)
- matrix[i] = (i%5 ? 0 : 1);
-}
+ Base(Base::identity())
+{ }
Matrix::Matrix(const float *m):
- flags(IDENTITY)
-{
- copy(m, m+16, matrix);
- check_flags();
-}
+ Base(m)
+{ }
-Matrix::Matrix(const double *m):
- flags(IDENTITY)
-{
- copy(m, m+16, matrix);
- check_flags();
-}
-
-void Matrix::check_flags()
-{
- const double *m = matrix;
- if(m[12]!=0 || m[13]!=0 || m[14]!=0)
- flags |= TRANSLATE;
- if(m[0]!=1)
- {
- flags |= SCALE;
- if(m[5]!=m[0] || m[10]!=m[0])
- flags |= ARBITARY;
- }
- if(m[1]!=0 || m[2]!=0 || m[4]!=0 || m[6]!=0 || m[8]!=0 || m[9]!=0)
- {
- flags |= ROTATE;
- double x_dot_y = m[0]*m[1]+m[4]*m[5]+m[8]*m[9];
- double x_dot_z = m[0]*m[2]+m[4]*m[6]+m[8]*m[10];
- double y_dot_z = m[1]*m[2]+m[5]*m[6]+m[9]*m[10];
- if(x_dot_y!=0 || x_dot_z!=0 || y_dot_z!=0)
- flags |= ARBITARY;
- }
- if(m[3]!=0 || m[7]!=0 || m[11]!=0 || m[15]!=1)
- flags |= ARBITARY;
-}
+Matrix::Matrix(const LinAl::Matrix<float, 4, 4> &other):
+ Base(other)
+{ }
void Matrix::multiply(const Matrix &other)
{
*this = *this*other;
}
-void Matrix::translate(double x, double y, double z)
-{
- multiply(translation(x, y, z));
-}
-
-void Matrix::rotate(double a, double x, double y, double z)
+void Matrix::translate(const Vector3 &t)
{
- multiply(rotation(a, x, y, z));
+ multiply(translation(t));
}
-void Matrix::rotate_deg(double a, double x, double y, double z)
+void Matrix::rotate(const Angle &a, const Vector3 &x)
{
- multiply(rotation_deg(a, x, y, z));
+ multiply(rotation(a, x));
}
-void Matrix::scale(double s)
+void Matrix::scale(const Vector3 &s)
{
multiply(scaling(s));
}
-void Matrix::scale(double x, double y, double z)
-{
- multiply(scaling(x, y, z));
-}
-
Matrix Matrix::operator*(const Matrix &other) const
{
- if(flags==IDENTITY)
- return other;
- else if(other.flags==IDENTITY)
- return *this;
- else if(flags==TRANSLATE && !(other.flags&ARBITARY))
- {
- Matrix result = other;
- result.matrix[12] += matrix[12];
- result.matrix[13] += matrix[13];
- result.matrix[14] += matrix[14];
- result.flags |= flags;
- return result;
- }
- else if(!(flags&ARBITARY) && other.flags==TRANSLATE)
- {
- Matrix result = *this;
- const double *m = other.matrix;
- result.matrix[12] += matrix[0]*m[12]+matrix[4]*m[13]+matrix[8]*m[14];
- result.matrix[13] += matrix[1]*m[12]+matrix[5]*m[13]+matrix[9]*m[14];
- result.matrix[14] += matrix[2]*m[12]+matrix[6]*m[13]+matrix[10]*m[14];
- result.flags |= other.flags;
- return result;
- }
- else
- {
- Matrix result;
- fill(result.matrix, result.matrix+16, 0.0);
- for(unsigned i=0; i<4; ++i)
- for(unsigned j=0; j<4; ++j)
- for(unsigned k=0; k<4; ++k)
- result.matrix[i+j*4] += matrix[i+k*4]*other.matrix[k+j*4];
- result.flags = flags|other.flags;
- return result;
- }
+ return static_cast<const Base &>(*this)*static_cast<const Base &>(other);
}
Matrix &Matrix::operator*=(const Matrix &other)
Vector4 Matrix::operator*(const Vector4 &vec) const
{
- if(flags==IDENTITY)
- return vec;
- else if(flags==TRANSLATE)
- return Vector4(vec.x+vec.w*matrix[12], vec.y+vec.w*matrix[13], vec.z+vec.w*matrix[14], vec.w);
- else if(flags==SCALE)
- return Vector4(vec.x*matrix[0], vec.y*matrix[5], vec.z*matrix[10], vec.w);
- else
- {
- Vector4 result;
- result.x = vec.x*matrix[0]+vec.y*matrix[4]+vec.z*matrix[8]+vec.w*matrix[12];
- result.y = vec.x*matrix[1]+vec.y*matrix[5]+vec.z*matrix[9]+vec.w*matrix[13];
- result.z = vec.x*matrix[2]+vec.y*matrix[6]+vec.z*matrix[10]+vec.w*matrix[14];
- result.w = vec.x*matrix[3]+vec.y*matrix[7]+vec.z*matrix[11]+vec.w*matrix[15];
- return result;
- }
-}
-
-double Matrix::operator[](unsigned i) const
-{
- if(i>=16)
- throw InvalidParameterValue("Matrix element index out of range");
- return matrix[i];
+ return static_cast<const Base &>(*this)*LinAl::Vector<float, 4>(vec);
}
-Matrix Matrix::translation(double x, double y, double z)
+Vector3 Matrix::operator*(const Vector3 &vec) const
{
- Matrix result;
- result.matrix[12] = x;
- result.matrix[13] = y;
- result.matrix[14] = z;
- result.flags |= TRANSLATE;
- return result;
+ return Vector3((*this)*Vector4(vec, 1.0f));
}
-Matrix Matrix::rotation(double a, double x, double y, double z)
+float Matrix::operator[](unsigned i) const
{
- double l = sqrt(x*x+y*y+z*z);
- x /= l;
- y /= l;
- z /= l;
- double c = cos(a);
- double s = sin(a);
-
- // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_given_an_axis_and_an_angle
- Matrix result;
- result.matrix[0] = c+x*x*(1-c);
- result.matrix[1] = y*x*(1-c)+z*s;
- result.matrix[2] = z*x*(1-c)-y*s;
- result.matrix[4] = x*y*(1-c)-z*s;
- result.matrix[5] = c+y*y*(1-c);
- result.matrix[6] = z*y*(1-c)+x*s;
- result.matrix[8] = x*z*(1-c)+y*s;
- result.matrix[9] = y*z*(1-c)-x*s;
- result.matrix[10] = c+z*z*(1-c);
- result.flags |= ROTATE;
- return result;
+ if(i>=16)
+ throw out_of_range("Matrix::operator[]");
+ return operator()(i%4, i/4);
}
-Matrix Matrix::rotation_deg(double a, double x, double y, double z)
+Matrix Matrix::translation(const Vector3 &t)
{
- return rotation(a*M_PI/180, x, y, z);
+ return Geometry::AffineTransformation<float, 3>::translation(t).get_matrix();
}
-Matrix Matrix::scaling(double s)
+Matrix Matrix::rotation(const Angle &a, const Vector3 &x)
{
- Matrix result;
- result.matrix[0] = s;
- result.matrix[5] = s;
- result.matrix[10] = s;
- result.flags |= SCALE;
- return result;
+ return Geometry::AffineTransformation<float, 3>::rotation(a, x).get_matrix();
}
-Matrix Matrix::scaling(double x, double y, double z)
+Matrix Matrix::scaling(const Vector3 &s)
{
- Matrix result;
- result.matrix[0] = x;
- result.matrix[5] = y;
- result.matrix[10] = z;
- result.flags |= SCALE|ARBITARY;
- return result;
+ return Geometry::AffineTransformation<float, 3>::scaling(s).get_matrix();
}
-Matrix Matrix::ortho(double l, double r, double b, double t, double n, double f)
+Matrix Matrix::ortho(float l, float r, float b, float t, float n, float f)
{
if(l==r || b==t || n==f)
- throw InvalidParameterValue("Orthogonal projection can't have zero dimension");
+ throw invalid_argument("Matrix::ortho");
Matrix result;
- result.matrix[0] = 2/(r-l);
- result.matrix[5] = 2/(t-b);
- result.matrix[10] = -2/(f-n);
- result.matrix[12] = -(r+l)/(r-l);
- result.matrix[13] = -(t+b)/(t-b);
- result.matrix[14] = -(f+n)/(f-n);
- result.flags = TRANSLATE|SCALE|ARBITARY;
+ result(0, 0) = 2/(r-l);
+ result(1, 1) = 2/(t-b);
+ result(2, 2) = -2/(f-n);
+ result(0, 3) = -(r+l)/(r-l);
+ result(1, 3) = -(t+b)/(t-b);
+ result(2, 3) = -(f+n)/(f-n);
return result;
}
-Matrix Matrix::ortho_centered(double w, double h)
+Matrix Matrix::ortho_centered(float w, float h)
{
return ortho(-w/2, w/2, -h/2, h/2, -1, 1);
}
-Matrix Matrix::ortho_bottomleft(double w, double h)
+Matrix Matrix::ortho_bottomleft(float w, float h)
{
return ortho(0, w, 0, h, -1, 1);
}
-Matrix Matrix::ortho_topleft(double w, double h)
+Matrix Matrix::ortho_topleft(float w, float h)
{
return ortho(0, w, h, 0, -1, 1);
}
-Matrix Matrix::frustum(double l, double r, double b, double t, double n, double f)
+Matrix Matrix::frustum(float l, float r, float b, float t, float n, float f)
{
if(l==r || b==t || n<=0 || f<=n)
- throw InvalidParameterValue("Invalid frustum parameters");
+ throw invalid_argument("Matrix::frustum");
Matrix result;
- result.matrix[0] = 2*n/(r-l);
- result.matrix[5] = 2*n/(t-b);
- result.matrix[8] = (r+l)/(r-l);
- result.matrix[9] = (t+b)/(t-b);
- result.matrix[10] = -(f+n)/(f-n);
- result.matrix[11] = -1;
- result.matrix[14] = -2*f*n/(f-n);
- result.matrix[15] = 0;
- result.flags = ARBITARY;
+ result(0, 0) = 2*n/(r-l);
+ result(1, 1) = 2*n/(t-b);
+ result(0, 2) = (r+l)/(r-l);
+ result(1, 2) = (t+b)/(t-b);
+ result(2, 2) = -(f+n)/(f-n);
+ result(3, 2) = -1;
+ result(2, 3) = -2*f*n/(f-n);
+ result(3, 3) = 0;
return result;
}
-Matrix Matrix::frustum_centered(double w, double h, double n, double f)
+Matrix Matrix::frustum_centered(float w, float h, float n, float f)
{
return frustum(-w/2, w/2, -h/2, h/2, n, f);
}
-Matrix Matrix::perspective(double h, double a, double n, double f)
+Matrix Matrix::perspective(const Angle &h, float a, float n, float f)
{
- double hh = tan(h/2)*n;
+ float hh = tan(h/2.0f)*n;
return frustum(-hh*a, hh*a, -hh, hh, n, f);
}
MatrixStack::MatrixStack(GLenum m):
mode(m)
{
+ matrices.reserve(mode==GL_MODELVIEW ? 32 : 4);
matrices.push_back(Matrix());
}
MatrixStack::MatrixStack():
mode(0)
{
+ matrices.reserve(32);
matrices.push_back(Matrix());
}
-const Matrix &MatrixStack::top()
+const Matrix &MatrixStack::top() const
{
return matrices.back();
}
void MatrixStack::pop()
{
if(matrices.size()==1)
- throw InvalidState("Can't pop the last matrix");
+ throw stack_underflow("MatrixStack::pop()");
matrices.pop_back();
update();
if(!mode)
return;
+ static Require _req(MSP_legacy_features);
+
if(mode!=current_mode)
{
glMatrixMode(mode);
current_mode = mode;
}
- glLoadMatrixd(matrices.back().data());
+ glLoadMatrixf(matrices.back().data());
}
MatrixStack &MatrixStack::operator=(const Matrix &m)
return ms;
}
-
-// Deprecated stuff
-
-MatrixStack *active_stack = &MatrixStack::modelview();
-
-void matrix_mode(MatrixMode m)
-{
- if(m==MODELVIEW)
- active_stack = &MatrixStack::modelview();
- else if(m==PROJECTION)
- active_stack = &MatrixStack::projection();
- else
- throw InvalidParameterValue("Texture matrices are not supported");
-}
-
-void load_identity()
-{
- *active_stack = Matrix();
-}
-
-void load_matrix(const float *matrix)
-{
- *active_stack = Matrix(matrix);
-}
-
-void load_matrix(const double *matrix)
-{
- *active_stack = Matrix(matrix);
-}
-
-void mult_matrix(const float *matrix)
-{
- *active_stack *= Matrix(matrix);
-}
-
-void mult_matrix(const double *matrix)
-{
- *active_stack *= Matrix(matrix);
-}
-
-void push_matrix()
-{
- active_stack->push();
-}
-
-void pop_matrix()
-{
- active_stack->pop();
-}
-
-void translate(float x, float y, float z)
-{
- *active_stack *= Matrix::translation(x, y, z);
-}
-
-void rotate(float a, float x, float y, float z)
-{
- *active_stack *= Matrix::rotation_deg(a, x, y, z);
-}
-
-void scale(float x, float y, float z)
-{
- *active_stack *= Matrix::scaling(x, y, z);
-}
-
-void scale_uniform(float s)
-{
- *active_stack *= Matrix::scaling(s);
-}
-
} // namespace GL
} // namespace Msp