17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 44a49301eSmrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 54a49301eSmrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 67117f1b4Smrg * 77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 97117f1b4Smrg * to deal in the Software without restriction, including without limitation 107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 127117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg * 147117f1b4Smrg * The above copyright notice and this permission notice shall be included 157117f1b4Smrg * in all copies or substantial portions of the Software. 167117f1b4Smrg * 177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 247117f1b4Smrg */ 257117f1b4Smrg 267117f1b4Smrg 277117f1b4Smrg/** 287117f1b4Smrg * \file matrix.c 297117f1b4Smrg * Matrix operations. 307117f1b4Smrg * 317117f1b4Smrg * \note 327117f1b4Smrg * -# 4x4 transformation matrices are stored in memory in column major order. 337117f1b4Smrg * -# Points/vertices are to be thought of as column vectors. 347117f1b4Smrg * -# Transformation of a point p by a matrix M is: p' = M * p 357117f1b4Smrg */ 367117f1b4Smrg 377117f1b4Smrg 387117f1b4Smrg#include "glheader.h" 397ec681f3Smrg 407117f1b4Smrg#include "context.h" 417117f1b4Smrg#include "enums.h" 427117f1b4Smrg#include "macros.h" 437117f1b4Smrg#include "matrix.h" 447117f1b4Smrg#include "mtypes.h" 457117f1b4Smrg#include "math/m_matrix.h" 4601e04c3fSmrg#include "util/bitscan.h" 477117f1b4Smrg 487117f1b4Smrg 497ec681f3Smrgstatic struct gl_matrix_stack * 507ec681f3Smrgget_named_matrix_stack(struct gl_context *ctx, GLenum mode, const char* caller) 517ec681f3Smrg{ 527ec681f3Smrg switch (mode) { 537ec681f3Smrg case GL_MODELVIEW: 547ec681f3Smrg return &ctx->ModelviewMatrixStack; 557ec681f3Smrg case GL_PROJECTION: 567ec681f3Smrg return &ctx->ProjectionMatrixStack; 577ec681f3Smrg case GL_TEXTURE: 587ec681f3Smrg /* This error check is disabled because if we're called from 597ec681f3Smrg * glPopAttrib() when the active texture unit is >= MaxTextureCoordUnits 607ec681f3Smrg * we'll generate an unexpected error. 617ec681f3Smrg * From the GL_ARB_vertex_shader spec it sounds like we should instead 627ec681f3Smrg * do error checking in other places when we actually try to access 637ec681f3Smrg * texture matrices beyond MaxTextureCoordUnits. 647ec681f3Smrg */ 657ec681f3Smrg#if 0 667ec681f3Smrg if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { 677ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 687ec681f3Smrg "glMatrixMode(invalid tex unit %d)", 697ec681f3Smrg ctx->Texture.CurrentUnit); 707ec681f3Smrg return; 717ec681f3Smrg } 727ec681f3Smrg#endif 737ec681f3Smrg assert(ctx->Texture.CurrentUnit < ARRAY_SIZE(ctx->TextureMatrixStack)); 747ec681f3Smrg return &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit]; 757ec681f3Smrg case GL_MATRIX0_ARB: 767ec681f3Smrg case GL_MATRIX1_ARB: 777ec681f3Smrg case GL_MATRIX2_ARB: 787ec681f3Smrg case GL_MATRIX3_ARB: 797ec681f3Smrg case GL_MATRIX4_ARB: 807ec681f3Smrg case GL_MATRIX5_ARB: 817ec681f3Smrg case GL_MATRIX6_ARB: 827ec681f3Smrg case GL_MATRIX7_ARB: 837ec681f3Smrg if (ctx->API == API_OPENGL_COMPAT 847ec681f3Smrg && (ctx->Extensions.ARB_vertex_program || 857ec681f3Smrg ctx->Extensions.ARB_fragment_program)) { 867ec681f3Smrg const GLuint m = mode - GL_MATRIX0_ARB; 877ec681f3Smrg if (m <= ctx->Const.MaxProgramMatrices) 887ec681f3Smrg return &ctx->ProgramMatrixStack[m]; 897ec681f3Smrg } 907ec681f3Smrg FALLTHROUGH; 917ec681f3Smrg default: 927ec681f3Smrg break; 937ec681f3Smrg } 947ec681f3Smrg if (mode >= GL_TEXTURE0 && mode < (GL_TEXTURE0 + ctx->Const.MaxTextureCoordUnits)) { 957ec681f3Smrg return &ctx->TextureMatrixStack[mode - GL_TEXTURE0]; 967ec681f3Smrg } 977ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 987ec681f3Smrg return NULL; 997ec681f3Smrg} 1007ec681f3Smrg 1017ec681f3Smrg 1027ec681f3Smrgstatic void matrix_frustum(struct gl_matrix_stack* stack, 1037ec681f3Smrg GLdouble left, GLdouble right, 1047ec681f3Smrg GLdouble bottom, GLdouble top, 1057ec681f3Smrg GLdouble nearval, GLdouble farval, 1067ec681f3Smrg const char* caller) 1077ec681f3Smrg{ 1087ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 1097ec681f3Smrg if (nearval <= 0.0 || 1107ec681f3Smrg farval <= 0.0 || 1117ec681f3Smrg nearval == farval || 1127ec681f3Smrg left == right || 1137ec681f3Smrg top == bottom) { 1147ec681f3Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 1157ec681f3Smrg return; 1167ec681f3Smrg } 1177ec681f3Smrg 1187ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 1197ec681f3Smrg 1207ec681f3Smrg _math_matrix_frustum(stack->Top, 1217ec681f3Smrg (GLfloat) left, (GLfloat) right, 1227ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 1237ec681f3Smrg (GLfloat) nearval, (GLfloat) farval); 1247ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 1257ec681f3Smrg} 1267ec681f3Smrg 1277ec681f3Smrg 1287117f1b4Smrg/** 1297117f1b4Smrg * Apply a perspective projection matrix. 1307117f1b4Smrg * 1317117f1b4Smrg * \param left left clipping plane coordinate. 1327117f1b4Smrg * \param right right clipping plane coordinate. 1337117f1b4Smrg * \param bottom bottom clipping plane coordinate. 1347117f1b4Smrg * \param top top clipping plane coordinate. 1357117f1b4Smrg * \param nearval distance to the near clipping plane. 1367117f1b4Smrg * \param farval distance to the far clipping plane. 1377117f1b4Smrg * 1387117f1b4Smrg * \sa glFrustum(). 1397117f1b4Smrg * 1407117f1b4Smrg * Flushes vertices and validates parameters. Calls _math_matrix_frustum() with 1417117f1b4Smrg * the top matrix of the current matrix stack and sets 1423464ebd5Sriastradh * __struct gl_contextRec::NewState. 1437117f1b4Smrg */ 1447117f1b4Smrgvoid GLAPIENTRY 1457117f1b4Smrg_mesa_Frustum( GLdouble left, GLdouble right, 1467117f1b4Smrg GLdouble bottom, GLdouble top, 1477117f1b4Smrg GLdouble nearval, GLdouble farval ) 1487117f1b4Smrg{ 1497117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1507ec681f3Smrg matrix_frustum(ctx->CurrentStack, 1517ec681f3Smrg (GLfloat) left, (GLfloat) right, 1527ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 1537ec681f3Smrg (GLfloat) nearval, (GLfloat) farval, 1547ec681f3Smrg "glFrustum"); 1557ec681f3Smrg} 156af69d88dSmrg 1577117f1b4Smrg 1587ec681f3Smrgvoid GLAPIENTRY 1597ec681f3Smrg_mesa_MatrixFrustumEXT( GLenum matrixMode, 1607ec681f3Smrg GLdouble left, GLdouble right, 1617ec681f3Smrg GLdouble bottom, GLdouble top, 1627ec681f3Smrg GLdouble nearval, GLdouble farval ) 1637ec681f3Smrg{ 1647ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 1657ec681f3Smrg struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 1667ec681f3Smrg "glMatrixFrustumEXT"); 1677ec681f3Smrg if (!stack) 1687ec681f3Smrg return; 1697ec681f3Smrg 1707ec681f3Smrg matrix_frustum(stack, 1717ec681f3Smrg (GLfloat) left, (GLfloat) right, 1727ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 1737ec681f3Smrg (GLfloat) nearval, (GLfloat) farval, 1747ec681f3Smrg "glMatrixFrustumEXT"); 1757ec681f3Smrg} 1767ec681f3Smrg 1777ec681f3Smrg 1787ec681f3Smrgstatic void 1797ec681f3Smrgmatrix_ortho(struct gl_matrix_stack* stack, 1807ec681f3Smrg GLdouble left, GLdouble right, 1817ec681f3Smrg GLdouble bottom, GLdouble top, 1827ec681f3Smrg GLdouble nearval, GLdouble farval, 1837ec681f3Smrg const char* caller) 1847ec681f3Smrg{ 1857ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 1867ec681f3Smrg 1877ec681f3Smrg if (MESA_VERBOSE & VERBOSE_API) 1887ec681f3Smrg _mesa_debug(ctx, "%s(%f, %f, %f, %f, %f, %f)\n", caller, 1897ec681f3Smrg left, right, bottom, top, nearval, farval); 1907ec681f3Smrg 1917ec681f3Smrg if (left == right || 1927ec681f3Smrg bottom == top || 1937ec681f3Smrg nearval == farval) 1947117f1b4Smrg { 1957ec681f3Smrg _mesa_error( ctx, GL_INVALID_VALUE, "%s", caller ); 1967117f1b4Smrg return; 1977117f1b4Smrg } 1987117f1b4Smrg 1997ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 2007ec681f3Smrg 2017ec681f3Smrg _math_matrix_ortho( stack->Top, 2027ec681f3Smrg (GLfloat) left, (GLfloat) right, 2037ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 2047ec681f3Smrg (GLfloat) nearval, (GLfloat) farval ); 2057ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 2067117f1b4Smrg} 2077117f1b4Smrg 2087117f1b4Smrg 2097117f1b4Smrg/** 2107117f1b4Smrg * Apply an orthographic projection matrix. 2117117f1b4Smrg * 2127117f1b4Smrg * \param left left clipping plane coordinate. 2137117f1b4Smrg * \param right right clipping plane coordinate. 2147117f1b4Smrg * \param bottom bottom clipping plane coordinate. 2157117f1b4Smrg * \param top top clipping plane coordinate. 2167117f1b4Smrg * \param nearval distance to the near clipping plane. 2177117f1b4Smrg * \param farval distance to the far clipping plane. 2187117f1b4Smrg * 2197117f1b4Smrg * \sa glOrtho(). 2207117f1b4Smrg * 2217117f1b4Smrg * Flushes vertices and validates parameters. Calls _math_matrix_ortho() with 2227117f1b4Smrg * the top matrix of the current matrix stack and sets 2233464ebd5Sriastradh * __struct gl_contextRec::NewState. 2247117f1b4Smrg */ 2257117f1b4Smrgvoid GLAPIENTRY 2267117f1b4Smrg_mesa_Ortho( GLdouble left, GLdouble right, 2277117f1b4Smrg GLdouble bottom, GLdouble top, 2287117f1b4Smrg GLdouble nearval, GLdouble farval ) 2297117f1b4Smrg{ 2307117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2317ec681f3Smrg matrix_ortho(ctx->CurrentStack, 2327ec681f3Smrg (GLfloat) left, (GLfloat) right, 2337ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 2347ec681f3Smrg (GLfloat) nearval, (GLfloat) farval, 2357ec681f3Smrg "glOrtho"); 2367ec681f3Smrg} 237af69d88dSmrg 2387117f1b4Smrg 2397ec681f3Smrgvoid GLAPIENTRY 2407ec681f3Smrg_mesa_MatrixOrthoEXT( GLenum matrixMode, 2417ec681f3Smrg GLdouble left, GLdouble right, 2427ec681f3Smrg GLdouble bottom, GLdouble top, 2437ec681f3Smrg GLdouble nearval, GLdouble farval ) 2447ec681f3Smrg{ 2457ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 2467ec681f3Smrg struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 2477ec681f3Smrg "glMatrixOrthoEXT"); 2487ec681f3Smrg if (!stack) 2497117f1b4Smrg return; 2507117f1b4Smrg 2517ec681f3Smrg matrix_ortho(stack, 2527ec681f3Smrg (GLfloat) left, (GLfloat) right, 2537ec681f3Smrg (GLfloat) bottom, (GLfloat) top, 2547ec681f3Smrg (GLfloat) nearval, (GLfloat) farval, 2557ec681f3Smrg "glMatrixOrthoEXT"); 2567117f1b4Smrg} 2577117f1b4Smrg 2587117f1b4Smrg 2597117f1b4Smrg/** 2607117f1b4Smrg * Set the current matrix stack. 2617117f1b4Smrg * 2627117f1b4Smrg * \param mode matrix stack. 2637117f1b4Smrg * 2647117f1b4Smrg * \sa glMatrixMode(). 2657117f1b4Smrg * 2667117f1b4Smrg * Flushes the vertices, validates the parameter and updates 2673464ebd5Sriastradh * __struct gl_contextRec::CurrentStack and gl_transform_attrib::MatrixMode 2683464ebd5Sriastradh * with the specified matrix stack. 2697117f1b4Smrg */ 2707117f1b4Smrgvoid GLAPIENTRY 2717117f1b4Smrg_mesa_MatrixMode( GLenum mode ) 2727117f1b4Smrg{ 2737ec681f3Smrg struct gl_matrix_stack * stack; 2747117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2757117f1b4Smrg 2767117f1b4Smrg if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE) 2777117f1b4Smrg return; 2787117f1b4Smrg 2797ec681f3Smrg if (mode >= GL_TEXTURE0 && mode < (GL_TEXTURE0 + ctx->Const.MaxTextureCoordUnits)) { 2807ec681f3Smrg stack = NULL; 2817ec681f3Smrg } else { 2827ec681f3Smrg stack = get_named_matrix_stack(ctx, mode, "glMatrixMode"); 2837ec681f3Smrg } 2847ec681f3Smrg 2857ec681f3Smrg if (stack) { 2867ec681f3Smrg ctx->CurrentStack = stack; 2877ec681f3Smrg ctx->Transform.MatrixMode = mode; 2887ec681f3Smrg ctx->PopAttribState |= GL_TRANSFORM_BIT; 2897ec681f3Smrg } 2907ec681f3Smrg} 2917ec681f3Smrg 2927ec681f3Smrg 2937ec681f3Smrgstatic void 2947ec681f3Smrgpush_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack, 2957ec681f3Smrg GLenum matrixMode, const char *func) 2967ec681f3Smrg{ 2977ec681f3Smrg if (stack->Depth + 1 >= stack->MaxDepth) { 2987ec681f3Smrg if (ctx->Transform.MatrixMode == GL_TEXTURE) { 2997ec681f3Smrg _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=GL_TEXTURE, unit=%d)", 3007ec681f3Smrg func, ctx->Texture.CurrentUnit); 3017ec681f3Smrg } else { 3027ec681f3Smrg _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=%s)", 3037ec681f3Smrg func, _mesa_enum_to_string(matrixMode)); 3047117f1b4Smrg } 3057ec681f3Smrg return; 3067ec681f3Smrg } 3077ec681f3Smrg 3087ec681f3Smrg if (stack->Depth + 1 >= stack->StackSize) { 3097ec681f3Smrg unsigned new_stack_size = stack->StackSize * 2; 3107ec681f3Smrg unsigned i; 3117ec681f3Smrg GLmatrix *new_stack = realloc(stack->Stack, 3127ec681f3Smrg sizeof(*new_stack) * new_stack_size); 3137ec681f3Smrg 3147ec681f3Smrg if (!new_stack) { 3157ec681f3Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 3167117f1b4Smrg return; 3177117f1b4Smrg } 3187ec681f3Smrg 3197ec681f3Smrg for (i = stack->StackSize; i < new_stack_size; i++) 3207ec681f3Smrg _math_matrix_ctr(&new_stack[i]); 3217ec681f3Smrg 3227ec681f3Smrg stack->Stack = new_stack; 3237ec681f3Smrg stack->StackSize = new_stack_size; 3247117f1b4Smrg } 3257117f1b4Smrg 3267ec681f3Smrg _math_matrix_push_copy(&stack->Stack[stack->Depth + 1], 3277ec681f3Smrg &stack->Stack[stack->Depth]); 3287ec681f3Smrg stack->Depth++; 3297ec681f3Smrg stack->Top = &(stack->Stack[stack->Depth]); 3307117f1b4Smrg} 3317117f1b4Smrg 3327117f1b4Smrg 3337117f1b4Smrg/** 3347117f1b4Smrg * Push the current matrix stack. 3357117f1b4Smrg * 3367117f1b4Smrg * \sa glPushMatrix(). 3377ec681f3Smrg * 3387117f1b4Smrg * Verifies the current matrix stack is not full, and duplicates the top-most 3393464ebd5Sriastradh * matrix in the stack. 3403464ebd5Sriastradh * Marks __struct gl_contextRec::NewState with the stack dirty flag. 3417117f1b4Smrg */ 3427117f1b4Smrgvoid GLAPIENTRY 3437117f1b4Smrg_mesa_PushMatrix( void ) 3447117f1b4Smrg{ 3457117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3467117f1b4Smrg struct gl_matrix_stack *stack = ctx->CurrentStack; 3477117f1b4Smrg 3487117f1b4Smrg if (MESA_VERBOSE&VERBOSE_API) 3497117f1b4Smrg _mesa_debug(ctx, "glPushMatrix %s\n", 35001e04c3fSmrg _mesa_enum_to_string(ctx->Transform.MatrixMode)); 3517117f1b4Smrg 3527ec681f3Smrg push_matrix(ctx, stack, ctx->Transform.MatrixMode, "glPushMatrix"); 3537ec681f3Smrg} 35401e04c3fSmrg 35501e04c3fSmrg 3567ec681f3Smrgvoid GLAPIENTRY 3577ec681f3Smrg_mesa_MatrixPushEXT( GLenum matrixMode ) 3587ec681f3Smrg{ 3597ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 3607ec681f3Smrg struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 3617ec681f3Smrg "glMatrixPushEXT"); 3627ec681f3Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 3637ec681f3Smrg if (stack) 3647ec681f3Smrg push_matrix(ctx, stack, matrixMode, "glMatrixPushEXT"); 3657ec681f3Smrg} 36601e04c3fSmrg 3677ec681f3Smrg 3687ec681f3Smrgstatic GLboolean 3697ec681f3Smrgpop_matrix( struct gl_context *ctx, struct gl_matrix_stack *stack ) 3707ec681f3Smrg{ 3717ec681f3Smrg if (stack->Depth == 0) 3727ec681f3Smrg return GL_FALSE; 3737ec681f3Smrg 3747ec681f3Smrg stack->Depth--; 3757ec681f3Smrg 3767ec681f3Smrg /* If the popped matrix is the same as the current one, treat it as 3777ec681f3Smrg * a no-op change. 3787ec681f3Smrg */ 3797ec681f3Smrg if (memcmp(stack->Top, &stack->Stack[stack->Depth], 3807ec681f3Smrg sizeof(GLmatrix))) { 3817ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 3827ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 38301e04c3fSmrg } 38401e04c3fSmrg 3857117f1b4Smrg stack->Top = &(stack->Stack[stack->Depth]); 3867ec681f3Smrg return GL_TRUE; 3877117f1b4Smrg} 3887117f1b4Smrg 3897117f1b4Smrg 3907117f1b4Smrg/** 3917117f1b4Smrg * Pop the current matrix stack. 3927117f1b4Smrg * 3937117f1b4Smrg * \sa glPopMatrix(). 3947ec681f3Smrg * 3957117f1b4Smrg * Flushes the vertices, verifies the current matrix stack is not empty, and 3963464ebd5Sriastradh * moves the stack head down. 3973464ebd5Sriastradh * Marks __struct gl_contextRec::NewState with the dirty stack flag. 3987117f1b4Smrg */ 3997117f1b4Smrgvoid GLAPIENTRY 4007117f1b4Smrg_mesa_PopMatrix( void ) 4017117f1b4Smrg{ 4027117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4037117f1b4Smrg struct gl_matrix_stack *stack = ctx->CurrentStack; 404af69d88dSmrg 4057117f1b4Smrg if (MESA_VERBOSE&VERBOSE_API) 4067117f1b4Smrg _mesa_debug(ctx, "glPopMatrix %s\n", 40701e04c3fSmrg _mesa_enum_to_string(ctx->Transform.MatrixMode)); 4087117f1b4Smrg 4097ec681f3Smrg if (!pop_matrix(ctx, stack)) { 4107117f1b4Smrg if (ctx->Transform.MatrixMode == GL_TEXTURE) { 4117ec681f3Smrg _mesa_error(ctx, GL_STACK_UNDERFLOW, 4127117f1b4Smrg "glPopMatrix(mode=GL_TEXTURE, unit=%d)", 4137117f1b4Smrg ctx->Texture.CurrentUnit); 4147117f1b4Smrg } 4157117f1b4Smrg else { 4167ec681f3Smrg _mesa_error(ctx, GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)", 41701e04c3fSmrg _mesa_enum_to_string(ctx->Transform.MatrixMode)); 4187117f1b4Smrg } 4197ec681f3Smrg } 4207ec681f3Smrg} 4217ec681f3Smrg 4227ec681f3Smrg 4237ec681f3Smrgvoid GLAPIENTRY 4247ec681f3Smrg_mesa_MatrixPopEXT( GLenum matrixMode ) 4257ec681f3Smrg{ 4267ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 4277ec681f3Smrg struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 4287ec681f3Smrg "glMatrixPopEXT"); 4297ec681f3Smrg if (!stack) 4307117f1b4Smrg return; 4317ec681f3Smrg 4327ec681f3Smrg if (!pop_matrix(ctx, stack)) { 4337ec681f3Smrg if (matrixMode == GL_TEXTURE) { 4347ec681f3Smrg _mesa_error(ctx, GL_STACK_UNDERFLOW, 4357ec681f3Smrg "glMatrixPopEXT(mode=GL_TEXTURE, unit=%d)", 4367ec681f3Smrg ctx->Texture.CurrentUnit); 4377ec681f3Smrg } 4387ec681f3Smrg else { 4397ec681f3Smrg _mesa_error(ctx, GL_STACK_UNDERFLOW, "glMatrixPopEXT(mode=%s)", 4407ec681f3Smrg _mesa_enum_to_string(matrixMode)); 4417ec681f3Smrg } 4427117f1b4Smrg } 4437ec681f3Smrg} 4447ec681f3Smrg 4457ec681f3Smrg 4467ec681f3Smrgvoid 4477ec681f3Smrg_mesa_load_identity_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack) 4487ec681f3Smrg{ 4497ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4507ec681f3Smrg 4517ec681f3Smrg _math_matrix_set_identity(stack->Top); 4527117f1b4Smrg ctx->NewState |= stack->DirtyFlag; 4537117f1b4Smrg} 4547117f1b4Smrg 4557117f1b4Smrg 4567117f1b4Smrg/** 4577117f1b4Smrg * Replace the current matrix with the identity matrix. 4587117f1b4Smrg * 4597117f1b4Smrg * \sa glLoadIdentity(). 4607117f1b4Smrg * 4613464ebd5Sriastradh * Flushes the vertices and calls _math_matrix_set_identity() with the 4623464ebd5Sriastradh * top-most matrix in the current stack. 4633464ebd5Sriastradh * Marks __struct gl_contextRec::NewState with the stack dirty flag. 4647117f1b4Smrg */ 4657117f1b4Smrgvoid GLAPIENTRY 4667117f1b4Smrg_mesa_LoadIdentity( void ) 4677117f1b4Smrg{ 4687117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 469af69d88dSmrg 4707117f1b4Smrg if (MESA_VERBOSE & VERBOSE_API) 471cdc920a0Smrg _mesa_debug(ctx, "glLoadIdentity()\n"); 4727117f1b4Smrg 4737ec681f3Smrg _mesa_load_identity_matrix(ctx, ctx->CurrentStack); 4747ec681f3Smrg} 4757ec681f3Smrg 4767ec681f3Smrg 4777ec681f3Smrgvoid GLAPIENTRY 4787ec681f3Smrg_mesa_MatrixLoadIdentityEXT( GLenum matrixMode ) 4797ec681f3Smrg{ 4807ec681f3Smrg struct gl_matrix_stack *stack; 4817ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 4827ec681f3Smrg stack = get_named_matrix_stack(ctx, matrixMode, "glMatrixLoadIdentityEXT"); 4837ec681f3Smrg if (!stack) 4847ec681f3Smrg return; 4857ec681f3Smrg 4867ec681f3Smrg _mesa_load_identity_matrix(ctx, stack); 4877ec681f3Smrg} 4887ec681f3Smrg 4897ec681f3Smrg 4907ec681f3Smrgvoid 4917ec681f3Smrg_mesa_load_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack, 4927ec681f3Smrg const GLfloat *m) 4937ec681f3Smrg{ 4947ec681f3Smrg if (memcmp(m, stack->Top->m, 16 * sizeof(GLfloat)) != 0) { 4957ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4967ec681f3Smrg _math_matrix_loadf(stack->Top, m); 4977ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 4987ec681f3Smrg } 4997ec681f3Smrg} 5007ec681f3Smrg 5017ec681f3Smrg 5027ec681f3Smrgstatic void 5037ec681f3Smrgmatrix_load(struct gl_context *ctx, struct gl_matrix_stack *stack, 5047ec681f3Smrg const GLfloat *m, const char* caller) 5057ec681f3Smrg{ 5067ec681f3Smrg if (!m) return; 5077ec681f3Smrg if (MESA_VERBOSE & VERBOSE_API) 5087ec681f3Smrg _mesa_debug(ctx, 5097ec681f3Smrg "%s(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 5107ec681f3Smrg caller, 5117ec681f3Smrg m[0], m[4], m[8], m[12], 5127ec681f3Smrg m[1], m[5], m[9], m[13], 5137ec681f3Smrg m[2], m[6], m[10], m[14], 5147ec681f3Smrg m[3], m[7], m[11], m[15]); 5157ec681f3Smrg 5167ec681f3Smrg _mesa_load_matrix(ctx, stack, m); 5177117f1b4Smrg} 5187117f1b4Smrg 5197117f1b4Smrg 5207117f1b4Smrg/** 5217117f1b4Smrg * Replace the current matrix with a given matrix. 5227117f1b4Smrg * 5237117f1b4Smrg * \param m matrix. 5247117f1b4Smrg * 5257117f1b4Smrg * \sa glLoadMatrixf(). 5267117f1b4Smrg * 5273464ebd5Sriastradh * Flushes the vertices and calls _math_matrix_loadf() with the top-most 5283464ebd5Sriastradh * matrix in the current stack and the given matrix. 5293464ebd5Sriastradh * Marks __struct gl_contextRec::NewState with the dirty stack flag. 5307117f1b4Smrg */ 5317117f1b4Smrgvoid GLAPIENTRY 5327117f1b4Smrg_mesa_LoadMatrixf( const GLfloat *m ) 5337117f1b4Smrg{ 5347117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5357ec681f3Smrg matrix_load(ctx, ctx->CurrentStack, m, "glLoadMatrix"); 5367ec681f3Smrg} 5377ec681f3Smrg 5387ec681f3Smrg 5397ec681f3Smrg/** 5407ec681f3Smrg * Replace the named matrix with a given matrix. 5417ec681f3Smrg * 5427ec681f3Smrg * \param matrixMode matrix to replace 5437ec681f3Smrg * \param m matrix 5447ec681f3Smrg * 5457ec681f3Smrg * \sa glLoadMatrixf(). 5467ec681f3Smrg */ 5477ec681f3Smrgvoid GLAPIENTRY 5487ec681f3Smrg_mesa_MatrixLoadfEXT( GLenum matrixMode, const GLfloat *m ) 5497ec681f3Smrg{ 5507ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 5517ec681f3Smrg struct gl_matrix_stack * stack = 5527ec681f3Smrg get_named_matrix_stack(ctx, matrixMode, "glMatrixLoadfEXT"); 5537ec681f3Smrg if (!stack) 5547ec681f3Smrg return; 5557ec681f3Smrg 5567ec681f3Smrg matrix_load(ctx, stack, m, "glMatrixLoadfEXT"); 5577ec681f3Smrg} 5587ec681f3Smrg 5597ec681f3Smrg 5607ec681f3Smrgstatic void 5617ec681f3Smrgmatrix_mult(struct gl_matrix_stack *stack, const GLfloat *m, const char* caller) 5627ec681f3Smrg{ 5637ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 5647ec681f3Smrg if (!m || 5657ec681f3Smrg (m[0] == 1 && m[1] == 0 && m[2] == 0 && m[3] == 0 && 5667ec681f3Smrg m[4] == 0 && m[5] == 1 && m[6] == 0 && m[7] == 0 && 5677ec681f3Smrg m[8] == 0 && m[9] == 0 && m[10] == 1 && m[11] == 0 && 5687ec681f3Smrg m[12] == 0 && m[13] == 0 && m[14] == 0 && m[15] == 1)) 5697ec681f3Smrg return; 5707117f1b4Smrg if (MESA_VERBOSE & VERBOSE_API) 5717117f1b4Smrg _mesa_debug(ctx, 5727ec681f3Smrg "%s(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 5737ec681f3Smrg caller, 5747117f1b4Smrg m[0], m[4], m[8], m[12], 5757117f1b4Smrg m[1], m[5], m[9], m[13], 5767117f1b4Smrg m[2], m[6], m[10], m[14], 5777117f1b4Smrg m[3], m[7], m[11], m[15]); 5787117f1b4Smrg 5797ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 5807ec681f3Smrg _math_matrix_mul_floats(stack->Top, m); 5817ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 5827117f1b4Smrg} 5837117f1b4Smrg 5847117f1b4Smrg 5857117f1b4Smrg/** 5867117f1b4Smrg * Multiply the current matrix with a given matrix. 5877117f1b4Smrg * 5887117f1b4Smrg * \param m matrix. 5897117f1b4Smrg * 5907117f1b4Smrg * \sa glMultMatrixf(). 5917117f1b4Smrg * 5927117f1b4Smrg * Flushes the vertices and calls _math_matrix_mul_floats() with the top-most 5937117f1b4Smrg * matrix in the current stack and the given matrix. Marks 5943464ebd5Sriastradh * __struct gl_contextRec::NewState with the dirty stack flag. 5957117f1b4Smrg */ 5967117f1b4Smrgvoid GLAPIENTRY 5977117f1b4Smrg_mesa_MultMatrixf( const GLfloat *m ) 5987117f1b4Smrg{ 5997117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6007ec681f3Smrg matrix_mult(ctx->CurrentStack, m, "glMultMatrix"); 6017ec681f3Smrg} 602af69d88dSmrg 6037ec681f3Smrg 6047ec681f3Smrgvoid GLAPIENTRY 6057ec681f3Smrg_mesa_MatrixMultfEXT( GLenum matrixMode, const GLfloat *m ) 6067ec681f3Smrg{ 6077ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 6087ec681f3Smrg struct gl_matrix_stack * stack = 6097ec681f3Smrg get_named_matrix_stack(ctx, matrixMode, "glMatrixMultfEXT"); 6107ec681f3Smrg if (!stack) 6117ec681f3Smrg return; 6127ec681f3Smrg 6137ec681f3Smrg matrix_mult(stack, m, "glMultMatrix"); 6147ec681f3Smrg} 6157ec681f3Smrg 6167ec681f3Smrg 6177ec681f3Smrgstatic void 6187ec681f3Smrgmatrix_rotate(struct gl_matrix_stack *stack, GLfloat angle, 6197ec681f3Smrg GLfloat x, GLfloat y, GLfloat z, const char* caller) 6207ec681f3Smrg{ 6217ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 6227ec681f3Smrg 6237ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 6247ec681f3Smrg if (angle != 0.0F) { 6257ec681f3Smrg _math_matrix_rotate(stack->Top, angle, x, y, z); 6267ec681f3Smrg ctx->NewState |=stack->DirtyFlag; 6277ec681f3Smrg } 6287117f1b4Smrg} 6297117f1b4Smrg 6307117f1b4Smrg 6317117f1b4Smrg/** 6327117f1b4Smrg * Multiply the current matrix with a rotation matrix. 6337117f1b4Smrg * 6347117f1b4Smrg * \param angle angle of rotation, in degrees. 6357117f1b4Smrg * \param x rotation vector x coordinate. 6367117f1b4Smrg * \param y rotation vector y coordinate. 6377117f1b4Smrg * \param z rotation vector z coordinate. 6387117f1b4Smrg * 6397117f1b4Smrg * \sa glRotatef(). 6407117f1b4Smrg * 6417117f1b4Smrg * Flushes the vertices and calls _math_matrix_rotate() with the top-most 6427117f1b4Smrg * matrix in the current stack and the given parameters. Marks 6433464ebd5Sriastradh * __struct gl_contextRec::NewState with the dirty stack flag. 6447117f1b4Smrg */ 6457117f1b4Smrgvoid GLAPIENTRY 6467117f1b4Smrg_mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) 6477117f1b4Smrg{ 6487117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6497ec681f3Smrg matrix_rotate(ctx->CurrentStack, angle, x, y, z, "glRotatef"); 6507ec681f3Smrg} 651af69d88dSmrg 6527ec681f3Smrg 6537ec681f3Smrgvoid GLAPIENTRY 6547ec681f3Smrg_mesa_MatrixRotatefEXT( GLenum matrixMode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) 6557ec681f3Smrg{ 6567ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 6577ec681f3Smrg struct gl_matrix_stack *stack = 6587ec681f3Smrg get_named_matrix_stack(ctx, matrixMode, "glMatrixRotatefEXT"); 6597ec681f3Smrg if (!stack) 6607ec681f3Smrg return; 6617ec681f3Smrg 6627ec681f3Smrg matrix_rotate(stack, angle, x, y, z, "glMatrixRotatefEXT"); 6637117f1b4Smrg} 6647117f1b4Smrg 6657117f1b4Smrg 6667117f1b4Smrg/** 6677117f1b4Smrg * Multiply the current matrix with a general scaling matrix. 6687117f1b4Smrg * 6697117f1b4Smrg * \param x x axis scale factor. 6707117f1b4Smrg * \param y y axis scale factor. 6717117f1b4Smrg * \param z z axis scale factor. 6727117f1b4Smrg * 6737117f1b4Smrg * \sa glScalef(). 6747117f1b4Smrg * 6757117f1b4Smrg * Flushes the vertices and calls _math_matrix_scale() with the top-most 6767117f1b4Smrg * matrix in the current stack and the given parameters. Marks 6773464ebd5Sriastradh * __struct gl_contextRec::NewState with the dirty stack flag. 6787117f1b4Smrg */ 6797117f1b4Smrgvoid GLAPIENTRY 6807117f1b4Smrg_mesa_Scalef( GLfloat x, GLfloat y, GLfloat z ) 6817117f1b4Smrg{ 6827117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 683af69d88dSmrg 6847ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 6857117f1b4Smrg _math_matrix_scale( ctx->CurrentStack->Top, x, y, z); 6867117f1b4Smrg ctx->NewState |= ctx->CurrentStack->DirtyFlag; 6877117f1b4Smrg} 6887117f1b4Smrg 6897117f1b4Smrg 6907ec681f3Smrgvoid GLAPIENTRY 6917ec681f3Smrg_mesa_MatrixScalefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ) 6927ec681f3Smrg{ 6937ec681f3Smrg struct gl_matrix_stack *stack; 6947ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 6957ec681f3Smrg 6967ec681f3Smrg stack = get_named_matrix_stack(ctx, matrixMode, "glMatrixScalefEXT"); 6977ec681f3Smrg if (!stack) 6987ec681f3Smrg return; 6997ec681f3Smrg 7007ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 7017ec681f3Smrg _math_matrix_scale(stack->Top, x, y, z); 7027ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 7037ec681f3Smrg} 7047ec681f3Smrg 7057ec681f3Smrg 7067117f1b4Smrg/** 7077117f1b4Smrg * Multiply the current matrix with a translation matrix. 7087117f1b4Smrg * 7097117f1b4Smrg * \param x translation vector x coordinate. 7107117f1b4Smrg * \param y translation vector y coordinate. 7117117f1b4Smrg * \param z translation vector z coordinate. 7127117f1b4Smrg * 7137117f1b4Smrg * \sa glTranslatef(). 7147117f1b4Smrg * 7157117f1b4Smrg * Flushes the vertices and calls _math_matrix_translate() with the top-most 7167117f1b4Smrg * matrix in the current stack and the given parameters. Marks 7173464ebd5Sriastradh * __struct gl_contextRec::NewState with the dirty stack flag. 7187117f1b4Smrg */ 7197117f1b4Smrgvoid GLAPIENTRY 7207117f1b4Smrg_mesa_Translatef( GLfloat x, GLfloat y, GLfloat z ) 7217117f1b4Smrg{ 7227117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 723af69d88dSmrg 7247ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 7257117f1b4Smrg _math_matrix_translate( ctx->CurrentStack->Top, x, y, z); 7267117f1b4Smrg ctx->NewState |= ctx->CurrentStack->DirtyFlag; 7277117f1b4Smrg} 7287117f1b4Smrg 7297ec681f3Smrg 7307ec681f3Smrgvoid GLAPIENTRY 7317ec681f3Smrg_mesa_MatrixTranslatefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ) 7327ec681f3Smrg{ 7337ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 7347ec681f3Smrg struct gl_matrix_stack *stack = 7357ec681f3Smrg get_named_matrix_stack(ctx, matrixMode, "glMatrixTranslatefEXT"); 7367ec681f3Smrg if (!stack) 7377ec681f3Smrg return; 7387ec681f3Smrg 7397ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 7407ec681f3Smrg _math_matrix_translate(stack->Top, x, y, z); 7417ec681f3Smrg ctx->NewState |= stack->DirtyFlag; 7427ec681f3Smrg} 7437ec681f3Smrg 7447ec681f3Smrg 7457117f1b4Smrgvoid GLAPIENTRY 7467117f1b4Smrg_mesa_LoadMatrixd( const GLdouble *m ) 7477117f1b4Smrg{ 7487117f1b4Smrg GLint i; 7497117f1b4Smrg GLfloat f[16]; 7507117f1b4Smrg if (!m) return; 7517117f1b4Smrg for (i = 0; i < 16; i++) 7527117f1b4Smrg f[i] = (GLfloat) m[i]; 7537117f1b4Smrg _mesa_LoadMatrixf(f); 7547117f1b4Smrg} 7557117f1b4Smrg 7567ec681f3Smrg 7577ec681f3Smrgvoid GLAPIENTRY 7587ec681f3Smrg_mesa_MatrixLoaddEXT( GLenum matrixMode, const GLdouble *m ) 7597ec681f3Smrg{ 7607ec681f3Smrg GLfloat f[16]; 7617ec681f3Smrg if (!m) return; 7627ec681f3Smrg for (unsigned i = 0; i < 16; i++) 7637ec681f3Smrg f[i] = (GLfloat) m[i]; 7647ec681f3Smrg _mesa_MatrixLoadfEXT(matrixMode, f); 7657ec681f3Smrg} 7667ec681f3Smrg 7677ec681f3Smrg 7687117f1b4Smrgvoid GLAPIENTRY 7697117f1b4Smrg_mesa_MultMatrixd( const GLdouble *m ) 7707117f1b4Smrg{ 7717117f1b4Smrg GLint i; 7727117f1b4Smrg GLfloat f[16]; 7737117f1b4Smrg if (!m) return; 7747117f1b4Smrg for (i = 0; i < 16; i++) 7757117f1b4Smrg f[i] = (GLfloat) m[i]; 7767117f1b4Smrg _mesa_MultMatrixf( f ); 7777117f1b4Smrg} 7787117f1b4Smrg 7797117f1b4Smrg 7807ec681f3Smrgvoid GLAPIENTRY 7817ec681f3Smrg_mesa_MatrixMultdEXT( GLenum matrixMode, const GLdouble *m ) 7827ec681f3Smrg{ 7837ec681f3Smrg GLfloat f[16]; 7847ec681f3Smrg if (!m) return; 7857ec681f3Smrg for (unsigned i = 0; i < 16; i++) 7867ec681f3Smrg f[i] = (GLfloat) m[i]; 7877ec681f3Smrg _mesa_MatrixMultfEXT(matrixMode, f); 7887ec681f3Smrg} 7897ec681f3Smrg 7907ec681f3Smrg 7917117f1b4Smrgvoid GLAPIENTRY 7927117f1b4Smrg_mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) 7937117f1b4Smrg{ 7947117f1b4Smrg _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z); 7957117f1b4Smrg} 7967117f1b4Smrg 7977117f1b4Smrg 7987ec681f3Smrgvoid GLAPIENTRY 7997ec681f3Smrg_mesa_MatrixRotatedEXT( GLenum matrixMode, GLdouble angle, 8007ec681f3Smrg GLdouble x, GLdouble y, GLdouble z ) 8017ec681f3Smrg{ 8027ec681f3Smrg _mesa_MatrixRotatefEXT(matrixMode, (GLfloat) angle, 8037ec681f3Smrg (GLfloat) x, (GLfloat) y, (GLfloat) z); 8047ec681f3Smrg} 8057ec681f3Smrg 8067ec681f3Smrg 8077117f1b4Smrgvoid GLAPIENTRY 8087117f1b4Smrg_mesa_Scaled( GLdouble x, GLdouble y, GLdouble z ) 8097117f1b4Smrg{ 8107117f1b4Smrg _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z); 8117117f1b4Smrg} 8127117f1b4Smrg 8137117f1b4Smrg 8147ec681f3Smrgvoid GLAPIENTRY 8157ec681f3Smrg_mesa_MatrixScaledEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z ) 8167ec681f3Smrg{ 8177ec681f3Smrg _mesa_MatrixScalefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) z); 8187ec681f3Smrg} 8197ec681f3Smrg 8207ec681f3Smrg 8217117f1b4Smrgvoid GLAPIENTRY 8227117f1b4Smrg_mesa_Translated( GLdouble x, GLdouble y, GLdouble z ) 8237117f1b4Smrg{ 8247117f1b4Smrg _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z); 8257117f1b4Smrg} 8267117f1b4Smrg 8277117f1b4Smrg 8287ec681f3Smrgvoid GLAPIENTRY 8297ec681f3Smrg_mesa_MatrixTranslatedEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z ) 8307ec681f3Smrg{ 8317ec681f3Smrg _mesa_MatrixTranslatefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) z); 8327ec681f3Smrg} 8337ec681f3Smrg 8347ec681f3Smrg 8357117f1b4Smrgvoid GLAPIENTRY 836af69d88dSmrg_mesa_LoadTransposeMatrixf( const GLfloat *m ) 8377117f1b4Smrg{ 8387117f1b4Smrg GLfloat tm[16]; 8397117f1b4Smrg if (!m) return; 8407117f1b4Smrg _math_transposef(tm, m); 8417117f1b4Smrg _mesa_LoadMatrixf(tm); 8427117f1b4Smrg} 8437117f1b4Smrg 8447ec681f3Smrgvoid GLAPIENTRY 8457ec681f3Smrg_mesa_MatrixLoadTransposefEXT( GLenum matrixMode, const GLfloat *m ) 8467ec681f3Smrg{ 8477ec681f3Smrg GLfloat tm[16]; 8487ec681f3Smrg if (!m) return; 8497ec681f3Smrg _math_transposef(tm, m); 8507ec681f3Smrg _mesa_MatrixLoadfEXT(matrixMode, tm); 8517ec681f3Smrg} 8527117f1b4Smrg 8537117f1b4Smrgvoid GLAPIENTRY 854af69d88dSmrg_mesa_LoadTransposeMatrixd( const GLdouble *m ) 8557117f1b4Smrg{ 8567117f1b4Smrg GLfloat tm[16]; 8577117f1b4Smrg if (!m) return; 8587117f1b4Smrg _math_transposefd(tm, m); 8597117f1b4Smrg _mesa_LoadMatrixf(tm); 8607117f1b4Smrg} 8617117f1b4Smrg 8627ec681f3Smrgvoid GLAPIENTRY 8637ec681f3Smrg_mesa_MatrixLoadTransposedEXT( GLenum matrixMode, const GLdouble *m ) 8647ec681f3Smrg{ 8657ec681f3Smrg GLfloat tm[16]; 8667ec681f3Smrg if (!m) return; 8677ec681f3Smrg _math_transposefd(tm, m); 8687ec681f3Smrg _mesa_MatrixLoadfEXT(matrixMode, tm); 8697ec681f3Smrg} 8707117f1b4Smrg 8717117f1b4Smrgvoid GLAPIENTRY 872af69d88dSmrg_mesa_MultTransposeMatrixf( const GLfloat *m ) 8737117f1b4Smrg{ 8747117f1b4Smrg GLfloat tm[16]; 8757117f1b4Smrg if (!m) return; 8767117f1b4Smrg _math_transposef(tm, m); 8777117f1b4Smrg _mesa_MultMatrixf(tm); 8787117f1b4Smrg} 8797117f1b4Smrg 8807ec681f3Smrgvoid GLAPIENTRY 8817ec681f3Smrg_mesa_MatrixMultTransposefEXT( GLenum matrixMode, const GLfloat *m ) 8827ec681f3Smrg{ 8837ec681f3Smrg GLfloat tm[16]; 8847ec681f3Smrg if (!m) return; 8857ec681f3Smrg _math_transposef(tm, m); 8867ec681f3Smrg _mesa_MatrixMultfEXT(matrixMode, tm); 8877ec681f3Smrg} 8887117f1b4Smrg 8897117f1b4Smrgvoid GLAPIENTRY 890af69d88dSmrg_mesa_MultTransposeMatrixd( const GLdouble *m ) 8917117f1b4Smrg{ 8927117f1b4Smrg GLfloat tm[16]; 8937117f1b4Smrg if (!m) return; 8947117f1b4Smrg _math_transposefd(tm, m); 8957117f1b4Smrg _mesa_MultMatrixf(tm); 8967117f1b4Smrg} 8977117f1b4Smrg 8987ec681f3Smrgvoid GLAPIENTRY 8997ec681f3Smrg_mesa_MatrixMultTransposedEXT( GLenum matrixMode, const GLdouble *m ) 9007ec681f3Smrg{ 9017ec681f3Smrg GLfloat tm[16]; 9027ec681f3Smrg if (!m) return; 9037ec681f3Smrg _math_transposefd(tm, m); 9047ec681f3Smrg _mesa_MatrixMultfEXT(matrixMode, tm); 9057ec681f3Smrg} 9067117f1b4Smrg 9077117f1b4Smrg/**********************************************************************/ 9087117f1b4Smrg/** \name State management */ 9097117f1b4Smrg/*@{*/ 9107117f1b4Smrg 9117117f1b4Smrg 9127117f1b4Smrg/** 9137117f1b4Smrg * Update the projection matrix stack. 9147117f1b4Smrg * 9157117f1b4Smrg * \param ctx GL context. 9167117f1b4Smrg * 9177ec681f3Smrg * Recomputes user clip positions if necessary. 9187ec681f3Smrg * 9193464ebd5Sriastradh * \note This routine references __struct gl_contextRec::Tranform attribute 9203464ebd5Sriastradh * values to compute userclip positions in clip space, but is only called on 9217117f1b4Smrg * _NEW_PROJECTION. The _mesa_ClipPlane() function keeps these values up to 9223464ebd5Sriastradh * date across changes to the __struct gl_contextRec::Transform attributes. 9237117f1b4Smrg */ 9247117f1b4Smrgstatic void 9253464ebd5Sriastradhupdate_projection( struct gl_context *ctx ) 9267117f1b4Smrg{ 9277117f1b4Smrg /* Recompute clip plane positions in clipspace. This is also done 9287117f1b4Smrg * in _mesa_ClipPlane(). 9297117f1b4Smrg */ 9307ec681f3Smrg GLbitfield mask = ctx->Transform.ClipPlanesEnabled; 93101e04c3fSmrg 9327ec681f3Smrg if (mask) { 9337ec681f3Smrg /* make sure the inverse is up to date */ 9347ec681f3Smrg _math_matrix_analyse(ctx->ProjectionMatrixStack.Top); 9357117f1b4Smrg 9367ec681f3Smrg do { 9377ec681f3Smrg const int p = u_bit_scan(&mask); 9387117f1b4Smrg 9397ec681f3Smrg _mesa_transform_vector(ctx->Transform._ClipUserPlane[p], 9407ec681f3Smrg ctx->Transform.EyeUserPlane[p], 9417ec681f3Smrg ctx->ProjectionMatrixStack.Top->inv); 9427ec681f3Smrg } while (mask); 9437ec681f3Smrg } 9447117f1b4Smrg} 9457117f1b4Smrg 9467117f1b4Smrg 9477117f1b4Smrg/** 9487117f1b4Smrg * Updates the combined modelview-projection matrix. 9497117f1b4Smrg * 9507117f1b4Smrg * \param ctx GL context. 9517117f1b4Smrg * \param new_state new state bit mask. 9527117f1b4Smrg * 9537117f1b4Smrg * If there is a new model view matrix then analyzes it. If there is a new 9547117f1b4Smrg * projection matrix, updates it. Finally calls 9557117f1b4Smrg * calculate_model_project_matrix() to recalculate the modelview-projection 9567117f1b4Smrg * matrix. 9577117f1b4Smrg */ 9583464ebd5Sriastradhvoid _mesa_update_modelview_project( struct gl_context *ctx, GLuint new_state ) 9597117f1b4Smrg{ 960af69d88dSmrg if (new_state & _NEW_MODELVIEW) 9617117f1b4Smrg _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); 9627117f1b4Smrg 9637117f1b4Smrg if (new_state & _NEW_PROJECTION) 9647117f1b4Smrg update_projection( ctx ); 9657117f1b4Smrg 9667ec681f3Smrg /* Calculate ModelViewMatrix * ProjectionMatrix. */ 9677ec681f3Smrg _math_matrix_mul_matrix(&ctx->_ModelProjectMatrix, 9687ec681f3Smrg ctx->ProjectionMatrixStack.Top, 9697ec681f3Smrg ctx->ModelviewMatrixStack.Top); 9707117f1b4Smrg} 9717117f1b4Smrg 9727117f1b4Smrg/*@}*/ 9737117f1b4Smrg 9747117f1b4Smrg 9757117f1b4Smrg/**********************************************************************/ 9767117f1b4Smrg/** Matrix stack initialization */ 9777117f1b4Smrg/*@{*/ 9787117f1b4Smrg 9797117f1b4Smrg 9807117f1b4Smrg/** 9817117f1b4Smrg * Initialize a matrix stack. 9827117f1b4Smrg * 9837117f1b4Smrg * \param stack matrix stack. 9847117f1b4Smrg * \param maxDepth maximum stack depth. 9857117f1b4Smrg * \param dirtyFlag dirty flag. 9867ec681f3Smrg * 9877117f1b4Smrg * Allocates an array of \p maxDepth elements for the matrix stack and calls 988af69d88dSmrg * _math_matrix_ctr() for each element to initialize it. 9897117f1b4Smrg */ 9907117f1b4Smrgstatic void 99101e04c3fSmrginit_matrix_stack(struct gl_matrix_stack *stack, 99201e04c3fSmrg GLuint maxDepth, GLuint dirtyFlag) 9937117f1b4Smrg{ 9947117f1b4Smrg stack->Depth = 0; 9957117f1b4Smrg stack->MaxDepth = maxDepth; 9967117f1b4Smrg stack->DirtyFlag = dirtyFlag; 99701e04c3fSmrg /* The stack will be dynamically resized at glPushMatrix() time */ 99801e04c3fSmrg stack->Stack = calloc(1, sizeof(GLmatrix)); 99901e04c3fSmrg stack->StackSize = 1; 100001e04c3fSmrg _math_matrix_ctr(&stack->Stack[0]); 10017117f1b4Smrg stack->Top = stack->Stack; 10027117f1b4Smrg} 10037117f1b4Smrg 10047117f1b4Smrg/** 10057117f1b4Smrg * Free matrix stack. 10067ec681f3Smrg * 10077117f1b4Smrg * \param stack matrix stack. 10087117f1b4Smrg */ 10097117f1b4Smrgstatic void 10107117f1b4Smrgfree_matrix_stack( struct gl_matrix_stack *stack ) 10117117f1b4Smrg{ 1012af69d88dSmrg free(stack->Stack); 10137117f1b4Smrg stack->Stack = stack->Top = NULL; 101401e04c3fSmrg stack->StackSize = 0; 10157117f1b4Smrg} 10167117f1b4Smrg 10177117f1b4Smrg/*@}*/ 10187117f1b4Smrg 10197117f1b4Smrg 10207117f1b4Smrg/**********************************************************************/ 10217117f1b4Smrg/** \name Initialization */ 10227117f1b4Smrg/*@{*/ 10237117f1b4Smrg 10247117f1b4Smrg 10257117f1b4Smrg/** 10267117f1b4Smrg * Initialize the context matrix data. 10277117f1b4Smrg * 10287117f1b4Smrg * \param ctx GL context. 10297117f1b4Smrg * 10307117f1b4Smrg * Initializes each of the matrix stacks and the combined modelview-projection 10317117f1b4Smrg * matrix. 10327117f1b4Smrg */ 10333464ebd5Sriastradhvoid _mesa_init_matrix( struct gl_context * ctx ) 10347117f1b4Smrg{ 103501e04c3fSmrg GLuint i; 10367117f1b4Smrg 10377117f1b4Smrg /* Initialize matrix stacks */ 10387117f1b4Smrg init_matrix_stack(&ctx->ModelviewMatrixStack, MAX_MODELVIEW_STACK_DEPTH, 10397117f1b4Smrg _NEW_MODELVIEW); 10407117f1b4Smrg init_matrix_stack(&ctx->ProjectionMatrixStack, MAX_PROJECTION_STACK_DEPTH, 10417117f1b4Smrg _NEW_PROJECTION); 104201e04c3fSmrg for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++) 10437117f1b4Smrg init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH, 10447117f1b4Smrg _NEW_TEXTURE_MATRIX); 104501e04c3fSmrg for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++) 104601e04c3fSmrg init_matrix_stack(&ctx->ProgramMatrixStack[i], 10477117f1b4Smrg MAX_PROGRAM_MATRIX_STACK_DEPTH, _NEW_TRACK_MATRIX); 10487117f1b4Smrg ctx->CurrentStack = &ctx->ModelviewMatrixStack; 10497117f1b4Smrg 10507117f1b4Smrg /* Init combined Modelview*Projection matrix */ 10517117f1b4Smrg _math_matrix_ctr( &ctx->_ModelProjectMatrix ); 10527117f1b4Smrg} 10537117f1b4Smrg 10547117f1b4Smrg 10557117f1b4Smrg/** 10567117f1b4Smrg * Free the context matrix data. 10577ec681f3Smrg * 10587117f1b4Smrg * \param ctx GL context. 10597117f1b4Smrg * 10607ec681f3Smrg * Frees each of the matrix stacks. 10617117f1b4Smrg */ 10623464ebd5Sriastradhvoid _mesa_free_matrix_data( struct gl_context *ctx ) 10637117f1b4Smrg{ 106401e04c3fSmrg GLuint i; 10657117f1b4Smrg 10667117f1b4Smrg free_matrix_stack(&ctx->ModelviewMatrixStack); 10677117f1b4Smrg free_matrix_stack(&ctx->ProjectionMatrixStack); 106801e04c3fSmrg for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++) 10697117f1b4Smrg free_matrix_stack(&ctx->TextureMatrixStack[i]); 107001e04c3fSmrg for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++) 10717117f1b4Smrg free_matrix_stack(&ctx->ProgramMatrixStack[i]); 10727117f1b4Smrg 10737117f1b4Smrg} 10747117f1b4Smrg 10757117f1b4Smrg 10767ec681f3Smrg/** 10777117f1b4Smrg * Initialize the context transform attribute group. 10787117f1b4Smrg * 10797117f1b4Smrg * \param ctx GL context. 10807117f1b4Smrg * 10817117f1b4Smrg * \todo Move this to a new file with other 'transform' routines. 10827117f1b4Smrg */ 10833464ebd5Sriastradhvoid _mesa_init_transform( struct gl_context *ctx ) 10847117f1b4Smrg{ 1085af69d88dSmrg GLuint i; 10867117f1b4Smrg 10877117f1b4Smrg /* Transformation group */ 10887117f1b4Smrg ctx->Transform.MatrixMode = GL_MODELVIEW; 10897117f1b4Smrg ctx->Transform.Normalize = GL_FALSE; 10907117f1b4Smrg ctx->Transform.RescaleNormals = GL_FALSE; 10917117f1b4Smrg ctx->Transform.RasterPositionUnclipped = GL_FALSE; 1092af69d88dSmrg for (i=0;i<ctx->Const.MaxClipPlanes;i++) { 10937117f1b4Smrg ASSIGN_4V( ctx->Transform.EyeUserPlane[i], 0.0, 0.0, 0.0, 0.0 ); 10947117f1b4Smrg } 10957117f1b4Smrg ctx->Transform.ClipPlanesEnabled = 0; 10967117f1b4Smrg} 10977117f1b4Smrg 10987117f1b4Smrg 10997117f1b4Smrg/*@}*/ 1100