X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fmatrix.cpp;h=a4c36a022a9ecb338406a496760f12c1d0655540;hp=f5089285d63295458698e1c392511348fc34a696;hb=a4549c55a6d47129bd9e42c6a49a671b759ce6d9;hpb=f14435e58bfa0fa697a06ba9a454bb30cd37d9d8 diff --git a/source/matrix.cpp b/source/matrix.cpp index f5089285..a4c36a02 100644 --- a/source/matrix.cpp +++ b/source/matrix.cpp @@ -1,6 +1,8 @@ #include #include -#include +#include +#include +#include "error.h" #include "matrix.h" using namespace std; @@ -9,266 +11,109 @@ namespace Msp { 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(); -} - -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; -} - -void Matrix::multiply(const Matrix &other) -{ - *this = *this*other; -} - -void Matrix::translate(double x, double y, double z) -{ - multiply(translation(x, y, z)); -} + Base(m) +{ } -void Matrix::rotate(double a, double x, double y, double z) -{ - multiply(rotation(a, x, y, z)); -} +Matrix::Matrix(const LinAl::Matrix &other): + Base(other) +{ } -void Matrix::rotate_deg(double a, double x, double y, double z) +Matrix &Matrix::translate(const Vector3 &t) { - multiply(rotation_deg(a, x, y, z)); + return multiply(translation(t)); } -void Matrix::scale(double s) +Matrix &Matrix::rotate(const Angle &a, const Vector3 &x) { - multiply(scaling(s)); + return multiply(rotation(a, x)); } -void Matrix::scale(double x, double y, double z) +Matrix &Matrix::scale(const Vector3 &s) { - multiply(scaling(x, y, z)); + return multiply(scaling(s)); } -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; - } -} - -Matrix &Matrix::operator*=(const Matrix &other) -{ - multiply(other); - return *this; -} - -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 +float Matrix::operator[](unsigned i) const { if(i>=16) - throw InvalidParameterValue("Matrix element index out of range"); - return matrix[i]; -} - -Matrix Matrix::translation(double x, double y, double z) -{ - Matrix result; - result.matrix[12] = x; - result.matrix[13] = y; - result.matrix[14] = z; - result.flags |= TRANSLATE; - return result; -} - -Matrix Matrix::rotation(double a, double x, double y, double z) -{ - 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; + 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::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::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::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); } @@ -278,12 +123,14 @@ GLenum MatrixStack::current_mode = GL_MODELVIEW; 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()); } @@ -312,7 +159,7 @@ void MatrixStack::push() void MatrixStack::pop() { if(matrices.size()==1) - throw InvalidState("Can't pop the last matrix"); + throw stack_underflow("MatrixStack::pop()"); matrices.pop_back(); update(); @@ -323,13 +170,15 @@ void MatrixStack::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) @@ -356,75 +205,5 @@ MatrixStack &MatrixStack::projection() 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