This is matrix.c in view mode; [Download] [Up]
/* $Id: matrix.c,v 1.19 1997/05/30 02:21:43 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 2.3 * Copyright (C) 1995-1997 Brian Paul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log: matrix.c,v $ * Revision 1.19 1997/05/30 02:21:43 brianp * gl_PopMatrix() set ctx->New*Matrix flag incorrectly * * Revision 1.18 1997/05/28 04:06:03 brianp * implemented projection near/far value stack for Driver.NearFar() function * * Revision 1.17 1997/05/28 03:25:43 brianp * added precompiled header (PCH) support * * Revision 1.16 1997/05/01 01:39:40 brianp * replace sqrt() with GL_SQRT() * * Revision 1.15 1997/04/21 01:20:41 brianp * added MATRIX_2D_NO_ROT * * Revision 1.14 1997/04/20 20:28:49 brianp * replaced abort() with gl_problem() * * Revision 1.13 1997/04/20 16:31:08 brianp * added NearFar device driver function * * Revision 1.12 1997/04/20 16:18:15 brianp * added glOrtho and glFrustum API pointers * * Revision 1.11 1997/04/01 04:23:53 brianp * added gl_analyze_*_matrix() functions * * Revision 1.10 1997/02/10 19:47:53 brianp * moved buffer resize code out of gl_Viewport() into gl_ResizeBuffersMESA() * * Revision 1.9 1997/01/31 23:32:40 brianp * now clear depth buffer after reallocation due to window resize * * Revision 1.8 1997/01/29 19:06:04 brianp * removed extra, local definition of Identity[] matrix * * Revision 1.7 1997/01/28 22:19:17 brianp * new matrix inversion code from Stephane Rehel * * Revision 1.6 1996/12/22 17:53:11 brianp * faster invert_matrix() function from scotter@lafn.org * * Revision 1.5 1996/12/02 18:58:34 brianp * gl_rotation_matrix() now returns identity matrix if given a 0 rotation axis * * Revision 1.4 1996/09/27 01:29:05 brianp * added missing default cases to switches * * Revision 1.3 1996/09/15 14:18:37 brianp * now use GLframebuffer and GLvisual * * Revision 1.2 1996/09/14 06:46:04 brianp * better matmul() from Jacques Leroy * * Revision 1.1 1996/09/13 01:38:16 brianp * Initial revision * */ /* * Matrix operations * * * NOTES: * 1. 4x4 transformation matrices are stored in memory in column major order. * 2. Points/vertices are to be thought of as column vectors. * 3. Transformation of a point p by a matrix M is: p' = M * p * */ #ifdef PCH #include "all.h" #else #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "context.h" #include "dlist.h" #include "macros.h" #include "matrix.h" #include "mmath.h" #include "types.h" #endif static GLfloat Identity[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; static void print_matrix( const GLfloat m[16] ) { int i; for (i=0;i<4;i++) { printf("%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] ); } } /* * Perform a 4x4 matrix multiplication (product = a x b). * Input: a, b - matrices to multiply * Output: product - product of a and b * WARNING: (product != b) assumed * NOTE: (product == a) allowed */ static void matmul( GLfloat *product, const GLfloat *a, const GLfloat *b ) { /* This matmul was contributed by Thomas Malik */ GLint i; #define A(row,col) a[(col<<2)+row] #define B(row,col) b[(col<<2)+row] #define P(row,col) product[(col<<2)+row] /* i-te Zeile */ for (i = 0; i < 4; i++) { GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); } #undef A #undef B #undef P } /* * Compute the inverse of a 4x4 matrix. Contributed by scotter@lafn.org */ static void invert_matrix_general( const GLfloat *m, GLfloat *out ) { /* NB. OpenGL Matrices are COLUMN major. */ #define MAT(m,r,c) (m)[(c)*4+(r)] /* Here's some shorthand converting standard (row,column) to index. */ #define m11 MAT(m,0,0) #define m12 MAT(m,0,1) #define m13 MAT(m,0,2) #define m14 MAT(m,0,3) #define m21 MAT(m,1,0) #define m22 MAT(m,1,1) #define m23 MAT(m,1,2) #define m24 MAT(m,1,3) #define m31 MAT(m,2,0) #define m32 MAT(m,2,1) #define m33 MAT(m,2,2) #define m34 MAT(m,2,3) #define m41 MAT(m,3,0) #define m42 MAT(m,3,1) #define m43 MAT(m,3,2) #define m44 MAT(m,3,3) GLfloat det; GLfloat d12, d13, d23, d24, d34, d41; GLfloat tmp[16]; /* Allow out == in. */ /* Inverse = adjoint / det. (See linear algebra texts.)*/ /* pre-compute 2x2 dets for last two rows when computing */ /* cofactors of first two rows. */ d12 = (m31*m42-m41*m32); d13 = (m31*m43-m41*m33); d23 = (m32*m43-m42*m33); d24 = (m32*m44-m42*m34); d34 = (m33*m44-m43*m34); d41 = (m34*m41-m44*m31); tmp[0] = (m22 * d34 - m23 * d24 + m24 * d23); tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13); tmp[2] = (m21 * d24 + m22 * d41 + m24 * d12); tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12); /* Compute determinant as early as possible using these cofactors. */ det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3]; /* Run singularity test. */ if (det == 0.0F) { /* printf("invert_matrix: Warning: Singular matrix.\n"); */ MEMCPY( out, Identity, 16*sizeof(GLfloat) ); } else { GLfloat invDet = 1.0F / det; /* Compute rest of inverse. */ tmp[0] *= invDet; tmp[1] *= invDet; tmp[2] *= invDet; tmp[3] *= invDet; tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet; tmp[5] = (m11 * d34 + m13 * d41 + m14 * d13) * invDet; tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet; tmp[7] = (m11 * d23 - m12 * d13 + m13 * d12) * invDet; /* Pre-compute 2x2 dets for first two rows when computing */ /* cofactors of last two rows. */ d12 = m11*m22-m21*m12; d13 = m11*m23-m21*m13; d23 = m12*m23-m22*m13; d24 = m12*m24-m22*m14; d34 = m13*m24-m23*m14; d41 = m14*m21-m24*m11; tmp[8] = (m42 * d34 - m43 * d24 + m44 * d23) * invDet; tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet; tmp[10] = (m41 * d24 + m42 * d41 + m44 * d12) * invDet; tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet; tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet; tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13) * invDet; tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet; tmp[15] = (m31 * d23 - m32 * d13 + m33 * d12) * invDet; MEMCPY(out, tmp, 16*sizeof(GLfloat)); } #undef m11 #undef m12 #undef m13 #undef m14 #undef m21 #undef m22 #undef m23 #undef m24 #undef m31 #undef m32 #undef m33 #undef m34 #undef m41 #undef m42 #undef m43 #undef m44 #undef MAT } /* * Invert matrix m. This algorithm contributed by Stephane Rehel * <rehel@worldnet.fr> */ static void invert_matrix( const GLfloat *m, GLfloat *out ) { /* NB. OpenGL Matrices are COLUMN major. */ #define MAT(m,r,c) (m)[(c)*4+(r)] /* Here's some shorthand converting standard (row,column) to index. */ #define m11 MAT(m,0,0) #define m12 MAT(m,0,1) #define m13 MAT(m,0,2) #define m14 MAT(m,0,3) #define m21 MAT(m,1,0) #define m22 MAT(m,1,1) #define m23 MAT(m,1,2) #define m24 MAT(m,1,3) #define m31 MAT(m,2,0) #define m32 MAT(m,2,1) #define m33 MAT(m,2,2) #define m34 MAT(m,2,3) #define m41 MAT(m,3,0) #define m42 MAT(m,3,1) #define m43 MAT(m,3,2) #define m44 MAT(m,3,3) register GLfloat det; GLfloat tmp[16]; /* Allow out == in. */ if( m41 != 0. || m42 != 0. || m43 != 0. || m44 != 1. ) { invert_matrix_general(m, out); return; } /* Inverse = adjoint / det. (See linear algebra texts.)*/ tmp[0]= m22 * m33 - m23 * m32; tmp[1]= m23 * m31 - m21 * m33; tmp[2]= m21 * m32 - m22 * m31; /* Compute determinant as early as possible using these cofactors. */ det= m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2]; /* Run singularity test. */ if (det == 0.0F) { /* printf("invert_matrix: Warning: Singular matrix.\n"); */ MEMCPY( out, Identity, 16*sizeof(GLfloat) ); } else { GLfloat d12, d13, d23, d24, d34, d41; register GLfloat im11, im12, im13, im14; det= 1. / det; /* Compute rest of inverse. */ tmp[0] *= det; tmp[1] *= det; tmp[2] *= det; tmp[3] = 0.; im11= m11 * det; im12= m12 * det; im13= m13 * det; im14= m14 * det; tmp[4] = im13 * m32 - im12 * m33; tmp[5] = im11 * m33 - im13 * m31; tmp[6] = im12 * m31 - im11 * m32; tmp[7] = 0.; /* Pre-compute 2x2 dets for first two rows when computing */ /* cofactors of last two rows. */ d12 = im11*m22 - m21*im12; d13 = im11*m23 - m21*im13; d23 = im12*m23 - m22*im13; d24 = im12*m24 - m22*im14; d34 = im13*m24 - m23*im14; d41 = im14*m21 - m24*im11; tmp[8] = d23; tmp[9] = -d13; tmp[10] = d12; tmp[11] = 0.; tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23); tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13); tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12); tmp[15] = 1.; MEMCPY(out, tmp, 16*sizeof(GLfloat)); } #undef m11 #undef m12 #undef m13 #undef m14 #undef m21 #undef m22 #undef m23 #undef m24 #undef m31 #undef m32 #undef m33 #undef m34 #undef m41 #undef m42 #undef m43 #undef m44 #undef MAT } /* * Determine if the given matrix is the identity matrix. */ static GLboolean is_identity( const GLfloat m[16] ) { if ( m[0]==1.0F && m[4]==0.0F && m[ 8]==0.0F && m[12]==0.0F && m[1]==0.0F && m[5]==1.0F && m[ 9]==0.0F && m[13]==0.0F && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { return GL_TRUE; } else { return GL_FALSE; } } /* * Examine the current modelview matrix to determine its type. * Later we use the matrix type to optimize vertex transformations. */ void gl_analyze_modelview_matrix( GLcontext *ctx ) { const GLfloat *m = ctx->ModelViewMatrix; if (is_identity(m)) { ctx->ModelViewMatrixType = MATRIX_IDENTITY; } else if ( m[4]==0.0F && m[ 8]==0.0F && m[1]==0.0F && m[ 9]==0.0F && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->ModelViewMatrixType = MATRIX_2D_NO_ROT; } else if ( m[ 8]==0.0F && m[ 9]==0.0F && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->ModelViewMatrixType = MATRIX_2D; } else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->ModelViewMatrixType = MATRIX_3D; } else { ctx->ModelViewMatrixType = MATRIX_GENERAL; } invert_matrix( ctx->ModelViewMatrix, ctx->ModelViewInv ); ctx->NewModelViewMatrix = GL_FALSE; } /* * Examine the current projection matrix to determine its type. * Later we use the matrix type to optimize vertex transformations. */ void gl_analyze_projection_matrix( GLcontext *ctx ) { /* look for common-case ortho and perspective matrices */ const GLfloat *m = ctx->ProjectionMatrix; if (is_identity(m)) { ctx->ProjectionMatrixType = MATRIX_IDENTITY; } else if ( m[4]==0.0F && m[8] ==0.0F && m[1]==0.0F && m[9] ==0.0F && m[2]==0.0F && m[6]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->ProjectionMatrixType = MATRIX_ORTHO; } else if ( m[4]==0.0F && m[12]==0.0F && m[1]==0.0F && m[13]==0.0F && m[2]==0.0F && m[6]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) { ctx->ProjectionMatrixType = MATRIX_PERSPECTIVE; } else { ctx->ProjectionMatrixType = MATRIX_GENERAL; } ctx->NewProjectionMatrix = GL_FALSE; } /* * Examine the current texture matrix to determine its type. * Later we use the matrix type to optimize texture coordinate transformations. */ void gl_analyze_texture_matrix( GLcontext *ctx ) { const GLfloat *m = ctx->TextureMatrix; if (is_identity(m)) { ctx->TextureMatrixType = MATRIX_IDENTITY; } else if ( m[ 8]==0.0F && m[ 9]==0.0F && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->TextureMatrixType = MATRIX_2D; } else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) { ctx->TextureMatrixType = MATRIX_3D; } else { ctx->TextureMatrixType = MATRIX_GENERAL; } ctx->NewTextureMatrix = GL_FALSE; } void gl_Frustum( GLcontext *ctx, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearval, GLdouble farval ) { GLfloat x, y, a, b, c, d; GLfloat m[16]; if (nearval<=0.0 || farval<=0.0) { gl_error( ctx, GL_INVALID_VALUE, "glFrustum(near or far)" ); } x = (2.0*nearval) / (right-left); y = (2.0*nearval) / (top-bottom); a = (right+left) / (right-left); b = (top+bottom) / (top-bottom); c = -(farval+nearval) / ( farval-nearval); d = -(2.0*farval*nearval) / (farval-nearval); /* error? */ #define M(row,col) m[col*4+row] M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F; M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F; M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d; M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F; #undef M gl_MultMatrixf( ctx, m ); /* Need to keep a stack of near/far values in case the user push/pops * the projection matrix stack so that we can call Driver.NearFar() * after a pop. */ ctx->NearFarStack[ctx->ProjectionStackDepth][0] = nearval; ctx->NearFarStack[ctx->ProjectionStackDepth][1] = farval; if (ctx->Driver.NearFar) { (*ctx->Driver.NearFar)( ctx, nearval, farval ); } } void gl_Ortho( GLcontext *ctx, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearval, GLdouble farval ) { GLfloat x, y, z; GLfloat tx, ty, tz; GLfloat m[16]; x = 2.0 / (right-left); y = 2.0 / (top-bottom); z = -2.0 / (farval-nearval); tx = -(right+left) / (right-left); ty = -(top+bottom) / (top-bottom); tz = -(farval+nearval) / (farval-nearval); #define M(row,col) m[col*4+row] M(0,0) = x; M(0,1) = 0.0F; M(0,2) = 0.0F; M(0,3) = tx; M(1,0) = 0.0F; M(1,1) = y; M(1,2) = 0.0F; M(1,3) = ty; M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = z; M(2,3) = tz; M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F; #undef M gl_MultMatrixf( ctx, m ); if (ctx->Driver.NearFar) { (*ctx->Driver.NearFar)( ctx, nearval, farval ); } } void gl_MatrixMode( GLcontext *ctx, GLenum mode ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glMatrixMode" ); return; } switch (mode) { case GL_MODELVIEW: case GL_PROJECTION: case GL_TEXTURE: ctx->Transform.MatrixMode = mode; break; default: gl_error( ctx, GL_INVALID_ENUM, "glMatrixMode" ); } } void gl_PushMatrix( GLcontext *ctx ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glPushMatrix" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: if (ctx->ModelViewStackDepth>=MAX_MODELVIEW_STACK_DEPTH-1) { gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix"); return; } MEMCPY( ctx->ModelViewStack[ctx->ModelViewStackDepth], ctx->ModelViewMatrix, 16*sizeof(GLfloat) ); ctx->ModelViewStackDepth++; break; case GL_PROJECTION: if (ctx->ProjectionStackDepth>=MAX_PROJECTION_STACK_DEPTH) { gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix"); return; } MEMCPY( ctx->ProjectionStack[ctx->ProjectionStackDepth], ctx->ProjectionMatrix, 16*sizeof(GLfloat) ); ctx->ProjectionStackDepth++; /* Save near and far projection values */ ctx->NearFarStack[ctx->ProjectionStackDepth][0] = ctx->NearFarStack[ctx->ProjectionStackDepth-1][0]; ctx->NearFarStack[ctx->ProjectionStackDepth][1] = ctx->NearFarStack[ctx->ProjectionStackDepth-1][1]; break; case GL_TEXTURE: if (ctx->TextureStackDepth>=MAX_TEXTURE_STACK_DEPTH) { gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix"); return; } MEMCPY( ctx->TextureStack[ctx->TextureStackDepth], ctx->TextureMatrix, 16*sizeof(GLfloat) ); ctx->TextureStackDepth++; break; default: gl_problem(ctx, "Bad matrix mode in gl_PushMatrix"); } } void gl_PopMatrix( GLcontext *ctx ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glPopMatrix" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: if (ctx->ModelViewStackDepth==0) { gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix"); return; } ctx->ModelViewStackDepth--; MEMCPY( ctx->ModelViewMatrix, ctx->ModelViewStack[ctx->ModelViewStackDepth], 16*sizeof(GLfloat) ); ctx->NewModelViewMatrix = GL_TRUE; break; case GL_PROJECTION: if (ctx->ProjectionStackDepth==0) { gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix"); return; } ctx->ProjectionStackDepth--; MEMCPY( ctx->ProjectionMatrix, ctx->ProjectionStack[ctx->ProjectionStackDepth], 16*sizeof(GLfloat) ); ctx->NewProjectionMatrix = GL_TRUE; /* Device driver near/far values */ { GLfloat nearVal = ctx->NearFarStack[ctx->ProjectionStackDepth][0]; GLfloat farVal = ctx->NearFarStack[ctx->ProjectionStackDepth][1]; if (ctx->Driver.NearFar) { (*ctx->Driver.NearFar)( ctx, nearVal, farVal ); } } break; case GL_TEXTURE: if (ctx->TextureStackDepth==0) { gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix"); return; } ctx->TextureStackDepth--; MEMCPY( ctx->TextureMatrix, ctx->TextureStack[ctx->TextureStackDepth], 16*sizeof(GLfloat) ); ctx->NewTextureMatrix = GL_TRUE; break; default: gl_problem(ctx, "Bad matrix mode in gl_PopMatrix"); } } void gl_LoadIdentity( GLcontext *ctx ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glLoadIdentity" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: MEMCPY( ctx->ModelViewMatrix, Identity, 16*sizeof(GLfloat) ); MEMCPY( ctx->ModelViewInv, Identity, 16*sizeof(GLfloat) ); ctx->ModelViewMatrixType = MATRIX_IDENTITY; ctx->NewModelViewMatrix = GL_FALSE; break; case GL_PROJECTION: MEMCPY( ctx->ProjectionMatrix, Identity, 16*sizeof(GLfloat) ); ctx->ProjectionMatrixType = MATRIX_IDENTITY; ctx->NewProjectionMatrix = GL_FALSE; break; case GL_TEXTURE: MEMCPY( ctx->TextureMatrix, Identity, 16*sizeof(GLfloat) ); ctx->TextureMatrixType = MATRIX_IDENTITY; ctx->NewTextureMatrix = GL_FALSE; break; default: gl_problem(ctx, "Bad matrix mode in gl_LoadIdentity"); } } void gl_LoadMatrixf( GLcontext *ctx, const GLfloat *m ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glLoadMatrix" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: MEMCPY( ctx->ModelViewMatrix, m, 16*sizeof(GLfloat) ); ctx->NewModelViewMatrix = GL_TRUE; break; case GL_PROJECTION: MEMCPY( ctx->ProjectionMatrix, m, 16*sizeof(GLfloat) ); ctx->NewProjectionMatrix = GL_TRUE; break; case GL_TEXTURE: MEMCPY( ctx->TextureMatrix, m, 16*sizeof(GLfloat) ); ctx->NewTextureMatrix = GL_TRUE; break; default: gl_problem(ctx, "Bad matrix mode in gl_LoadMatrixf"); } } void gl_MultMatrixf( GLcontext *ctx, const GLfloat *m ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glMultMatrix" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: matmul( ctx->ModelViewMatrix, ctx->ModelViewMatrix, m ); ctx->NewModelViewMatrix = GL_TRUE; break; case GL_PROJECTION: matmul( ctx->ProjectionMatrix, ctx->ProjectionMatrix, m ); ctx->NewProjectionMatrix = GL_TRUE; break; case GL_TEXTURE: matmul( ctx->TextureMatrix, ctx->TextureMatrix, m ); ctx->NewTextureMatrix = GL_TRUE; break; default: gl_problem(ctx, "Bad matrix mode in gl_MultMatrixf"); } } /* * Generate a 4x4 transformation matrix from glRotate parameters. */ void gl_rotation_matrix( GLfloat angle, GLfloat x, GLfloat y, GLfloat z, GLfloat m[] ) { /* This function contributed by Erich Boleyn (erich@uruk.org) */ GLfloat mag, s, c; GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; s = sin( angle * DEG2RAD ); c = cos( angle * DEG2RAD ); mag = GL_SQRT( x*x + y*y + z*z ); if (mag == 0.0) { /* generate an identity matrix and return */ MEMCPY(m, Identity, sizeof(GLfloat)*16); return; } x /= mag; y /= mag; z /= mag; #define M(row,col) m[col*4+row] /* * Arbitrary axis rotation matrix. * * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation * (which is about the X-axis), and the two composite transforms * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary * from the arbitrary axis to the X-axis then back. They are * all elementary rotations. * * Rz' is a rotation about the Z-axis, to bring the axis vector * into the x-z plane. Then Ry' is applied, rotating about the * Y-axis to bring the axis vector parallel with the X-axis. The * rotation about the X-axis is then performed. Ry and Rz are * simply the respective inverse transforms to bring the arbitrary * axis back to it's original orientation. The first transforms * Rz' and Ry' are considered inverses, since the data from the * arbitrary axis gives you info on how to get to it, not how * to get away from it, and an inverse must be applied. * * The basic calculation used is to recognize that the arbitrary * axis vector (x, y, z), since it is of unit length, actually * represents the sines and cosines of the angles to rotate the * X-axis to the same orientation, with theta being the angle about * Z and phi the angle about Y (in the order described above) * as follows: * * cos ( theta ) = x / sqrt ( 1 - z^2 ) * sin ( theta ) = y / sqrt ( 1 - z^2 ) * * cos ( phi ) = sqrt ( 1 - z^2 ) * sin ( phi ) = z * * Note that cos ( phi ) can further be inserted to the above * formulas: * * cos ( theta ) = x / cos ( phi ) * sin ( theta ) = y / sin ( phi ) * * ...etc. Because of those relations and the standard trigonometric * relations, it is pssible to reduce the transforms down to what * is used below. It may be that any primary axis chosen will give the * same results (modulo a sign convention) using thie method. * * Particularly nice is to notice that all divisions that might * have caused trouble when parallel to certain planes or * axis go away with care paid to reducing the expressions. * After checking, it does perform correctly under all cases, since * in all the cases of division where the denominator would have * been zero, the numerator would have been zero as well, giving * the expected result. */ xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0F - c; M(0,0) = (one_c * xx) + c; M(0,1) = (one_c * xy) - zs; M(0,2) = (one_c * zx) + ys; M(0,3) = 0.0F; M(1,0) = (one_c * xy) + zs; M(1,1) = (one_c * yy) + c; M(1,2) = (one_c * yz) - xs; M(1,3) = 0.0F; M(2,0) = (one_c * zx) - ys; M(2,1) = (one_c * yz) + xs; M(2,2) = (one_c * zz) + c; M(2,3) = 0.0F; M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F; #undef M } void gl_Rotatef( GLcontext *ctx, GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) { GLfloat m[16]; gl_rotation_matrix( angle, x, y, z, m ); gl_MultMatrixf( ctx, m ); } /* * Execute a glScale call */ void gl_Scalef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z ) { GLfloat *m; if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glScale" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: m = ctx->ModelViewMatrix; ctx->NewModelViewMatrix = GL_TRUE; break; case GL_PROJECTION: m = ctx->ProjectionMatrix; ctx->NewProjectionMatrix = GL_TRUE; break; case GL_TEXTURE: m = ctx->TextureMatrix; ctx->NewTextureMatrix = GL_TRUE; break; default: gl_problem(ctx, "Bad matrix mode in gl_Scalef"); return; } m[0] *= x; m[4] *= y; m[8] *= z; m[1] *= x; m[5] *= y; m[9] *= z; m[2] *= x; m[6] *= y; m[10] *= z; m[3] *= x; m[7] *= y; m[11] *= z; } /* * Execute a glTranslate call */ void gl_Translatef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z ) { GLfloat *m; if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glTranslate" ); return; } switch (ctx->Transform.MatrixMode) { case GL_MODELVIEW: m = ctx->ModelViewMatrix; ctx->NewModelViewMatrix = GL_TRUE; break; case GL_PROJECTION: m = ctx->ProjectionMatrix; ctx->NewProjectionMatrix = GL_TRUE; break; case GL_TEXTURE: m = ctx->TextureMatrix; ctx->NewTextureMatrix = GL_TRUE; break; default: gl_problem(ctx, "Bad matrix mode in gl_Translatef"); return; } m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; } /* * Define a new viewport and reallocate auxillary buffers if the size of * the window (color buffer) has changed. */ void gl_Viewport( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height ) { if (width<0 || height<0) { gl_error( ctx, GL_INVALID_VALUE, "glViewport" ); return; } if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glViewport" ); return; } /* clamp width, and height to implementation dependent range */ width = CLAMP( width, 1, MAX_WIDTH ); height = CLAMP( height, 1, MAX_HEIGHT ); /* Save viewport */ ctx->Viewport.X = x; ctx->Viewport.Width = width; ctx->Viewport.Y = y; ctx->Viewport.Height = height; /* compute scale and bias values */ ctx->Viewport.Sx = (GLfloat) width / 2.0F; ctx->Viewport.Tx = ctx->Viewport.Sx + x; ctx->Viewport.Sy = (GLfloat) height / 2.0F; ctx->Viewport.Ty = ctx->Viewport.Sy + y; ctx->NewState |= NEW_ALL; /* just to be safe */ /* Check if window/buffer has been resized and if so, reallocate the * ancillary buffers. */ gl_ResizeBuffersMESA(ctx); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.