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