Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
      5  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  */
     25 
     26 
     27 /**
     28  * \file matrix.c
     29  * Matrix operations.
     30  *
     31  * \note
     32  * -# 4x4 transformation matrices are stored in memory in column major order.
     33  * -# Points/vertices are to be thought of as column vectors.
     34  * -# Transformation of a point p by a matrix M is: p' = M * p
     35  */
     36 
     37 
     38 #include "glheader.h"
     39 #include "imports.h"
     40 #include "context.h"
     41 #include "enums.h"
     42 #include "macros.h"
     43 #include "matrix.h"
     44 #include "mtypes.h"
     45 #include "math/m_matrix.h"
     46 #include "util/bitscan.h"
     47 
     48 
     49 /**
     50  * Apply a perspective projection matrix.
     51  *
     52  * \param left left clipping plane coordinate.
     53  * \param right right clipping plane coordinate.
     54  * \param bottom bottom clipping plane coordinate.
     55  * \param top top clipping plane coordinate.
     56  * \param nearval distance to the near clipping plane.
     57  * \param farval distance to the far clipping plane.
     58  *
     59  * \sa glFrustum().
     60  *
     61  * Flushes vertices and validates parameters. Calls _math_matrix_frustum() with
     62  * the top matrix of the current matrix stack and sets
     63  * __struct gl_contextRec::NewState.
     64  */
     65 void GLAPIENTRY
     66 _mesa_Frustum( GLdouble left, GLdouble right,
     67                GLdouble bottom, GLdouble top,
     68                GLdouble nearval, GLdouble farval )
     69 {
     70    GET_CURRENT_CONTEXT(ctx);
     71 
     72    FLUSH_VERTICES(ctx, 0);
     73 
     74    if (nearval <= 0.0 ||
     75        farval <= 0.0 ||
     76        nearval == farval ||
     77        left == right ||
     78        top == bottom)
     79    {
     80       _mesa_error( ctx,  GL_INVALID_VALUE, "glFrustum" );
     81       return;
     82    }
     83 
     84    _math_matrix_frustum( ctx->CurrentStack->Top,
     85                          (GLfloat) left, (GLfloat) right,
     86 			 (GLfloat) bottom, (GLfloat) top,
     87 			 (GLfloat) nearval, (GLfloat) farval );
     88    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
     89 }
     90 
     91 
     92 /**
     93  * Apply an orthographic projection matrix.
     94  *
     95  * \param left left clipping plane coordinate.
     96  * \param right right clipping plane coordinate.
     97  * \param bottom bottom clipping plane coordinate.
     98  * \param top top clipping plane coordinate.
     99  * \param nearval distance to the near clipping plane.
    100  * \param farval distance to the far clipping plane.
    101  *
    102  * \sa glOrtho().
    103  *
    104  * Flushes vertices and validates parameters. Calls _math_matrix_ortho() with
    105  * the top matrix of the current matrix stack and sets
    106  * __struct gl_contextRec::NewState.
    107  */
    108 void GLAPIENTRY
    109 _mesa_Ortho( GLdouble left, GLdouble right,
    110              GLdouble bottom, GLdouble top,
    111              GLdouble nearval, GLdouble farval )
    112 {
    113    GET_CURRENT_CONTEXT(ctx);
    114 
    115    FLUSH_VERTICES(ctx, 0);
    116 
    117    if (MESA_VERBOSE & VERBOSE_API)
    118       _mesa_debug(ctx, "glOrtho(%f, %f, %f, %f, %f, %f)\n",
    119                   left, right, bottom, top, nearval, farval);
    120 
    121    if (left == right ||
    122        bottom == top ||
    123        nearval == farval)
    124    {
    125       _mesa_error( ctx,  GL_INVALID_VALUE, "glOrtho" );
    126       return;
    127    }
    128 
    129    _math_matrix_ortho( ctx->CurrentStack->Top,
    130                        (GLfloat) left, (GLfloat) right,
    131 		       (GLfloat) bottom, (GLfloat) top,
    132 		       (GLfloat) nearval, (GLfloat) farval );
    133    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    134 }
    135 
    136 
    137 /**
    138  * Set the current matrix stack.
    139  *
    140  * \param mode matrix stack.
    141  *
    142  * \sa glMatrixMode().
    143  *
    144  * Flushes the vertices, validates the parameter and updates
    145  * __struct gl_contextRec::CurrentStack and gl_transform_attrib::MatrixMode
    146  * with the specified matrix stack.
    147  */
    148 void GLAPIENTRY
    149 _mesa_MatrixMode( GLenum mode )
    150 {
    151    GET_CURRENT_CONTEXT(ctx);
    152 
    153    if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE)
    154       return;
    155 
    156    switch (mode) {
    157    case GL_MODELVIEW:
    158       ctx->CurrentStack = &ctx->ModelviewMatrixStack;
    159       break;
    160    case GL_PROJECTION:
    161       ctx->CurrentStack = &ctx->ProjectionMatrixStack;
    162       break;
    163    case GL_TEXTURE:
    164       /* This error check is disabled because if we're called from
    165        * glPopAttrib() when the active texture unit is >= MaxTextureCoordUnits
    166        * we'll generate an unexpected error.
    167        * From the GL_ARB_vertex_shader spec it sounds like we should instead
    168        * do error checking in other places when we actually try to access
    169        * texture matrices beyond MaxTextureCoordUnits.
    170        */
    171 #if 0
    172       if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
    173          _mesa_error(ctx, GL_INVALID_OPERATION,
    174                      "glMatrixMode(invalid tex unit %d)",
    175                      ctx->Texture.CurrentUnit);
    176          return;
    177       }
    178 #endif
    179       assert(ctx->Texture.CurrentUnit < ARRAY_SIZE(ctx->TextureMatrixStack));
    180       ctx->CurrentStack = &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit];
    181       break;
    182    case GL_MATRIX0_ARB:
    183    case GL_MATRIX1_ARB:
    184    case GL_MATRIX2_ARB:
    185    case GL_MATRIX3_ARB:
    186    case GL_MATRIX4_ARB:
    187    case GL_MATRIX5_ARB:
    188    case GL_MATRIX6_ARB:
    189    case GL_MATRIX7_ARB:
    190       if (ctx->API == API_OPENGL_COMPAT
    191           && (ctx->Extensions.ARB_vertex_program ||
    192               ctx->Extensions.ARB_fragment_program)) {
    193          const GLuint m = mode - GL_MATRIX0_ARB;
    194          if (m > ctx->Const.MaxProgramMatrices) {
    195             _mesa_error(ctx, GL_INVALID_ENUM,
    196                         "glMatrixMode(GL_MATRIX%d_ARB)", m);
    197             return;
    198          }
    199          ctx->CurrentStack = &ctx->ProgramMatrixStack[m];
    200       }
    201       else {
    202          _mesa_error( ctx,  GL_INVALID_ENUM, "glMatrixMode(mode)" );
    203          return;
    204       }
    205       break;
    206    default:
    207       _mesa_error( ctx,  GL_INVALID_ENUM, "glMatrixMode(mode)" );
    208       return;
    209    }
    210 
    211    ctx->Transform.MatrixMode = mode;
    212 }
    213 
    214 
    215 /**
    216  * Push the current matrix stack.
    217  *
    218  * \sa glPushMatrix().
    219  *
    220  * Verifies the current matrix stack is not full, and duplicates the top-most
    221  * matrix in the stack.
    222  * Marks __struct gl_contextRec::NewState with the stack dirty flag.
    223  */
    224 void GLAPIENTRY
    225 _mesa_PushMatrix( void )
    226 {
    227    GET_CURRENT_CONTEXT(ctx);
    228    struct gl_matrix_stack *stack = ctx->CurrentStack;
    229 
    230    if (MESA_VERBOSE&VERBOSE_API)
    231       _mesa_debug(ctx, "glPushMatrix %s\n",
    232                   _mesa_enum_to_string(ctx->Transform.MatrixMode));
    233 
    234    if (stack->Depth + 1 >= stack->MaxDepth) {
    235       if (ctx->Transform.MatrixMode == GL_TEXTURE) {
    236          _mesa_error(ctx,  GL_STACK_OVERFLOW,
    237                      "glPushMatrix(mode=GL_TEXTURE, unit=%d)",
    238                       ctx->Texture.CurrentUnit);
    239       }
    240       else {
    241          _mesa_error(ctx,  GL_STACK_OVERFLOW, "glPushMatrix(mode=%s)",
    242                      _mesa_enum_to_string(ctx->Transform.MatrixMode));
    243       }
    244       return;
    245    }
    246    if (stack->Depth + 1 >= stack->StackSize) {
    247       unsigned new_stack_size = stack->StackSize * 2;
    248       unsigned i;
    249       GLmatrix *new_stack = realloc(stack->Stack,
    250                                     sizeof(*new_stack) * new_stack_size);
    251 
    252       if (!new_stack) {
    253          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushMatrix()");
    254          return;
    255       }
    256 
    257       for (i = stack->StackSize; i < new_stack_size; i++)
    258          _math_matrix_ctr(&new_stack[i]);
    259 
    260       stack->Stack = new_stack;
    261       stack->StackSize = new_stack_size;
    262    }
    263 
    264    _math_matrix_copy( &stack->Stack[stack->Depth + 1],
    265                       &stack->Stack[stack->Depth] );
    266    stack->Depth++;
    267    stack->Top = &(stack->Stack[stack->Depth]);
    268    ctx->NewState |= stack->DirtyFlag;
    269 }
    270 
    271 
    272 /**
    273  * Pop the current matrix stack.
    274  *
    275  * \sa glPopMatrix().
    276  *
    277  * Flushes the vertices, verifies the current matrix stack is not empty, and
    278  * moves the stack head down.
    279  * Marks __struct gl_contextRec::NewState with the dirty stack flag.
    280  */
    281 void GLAPIENTRY
    282 _mesa_PopMatrix( void )
    283 {
    284    GET_CURRENT_CONTEXT(ctx);
    285    struct gl_matrix_stack *stack = ctx->CurrentStack;
    286 
    287    FLUSH_VERTICES(ctx, 0);
    288 
    289    if (MESA_VERBOSE&VERBOSE_API)
    290       _mesa_debug(ctx, "glPopMatrix %s\n",
    291                   _mesa_enum_to_string(ctx->Transform.MatrixMode));
    292 
    293    if (stack->Depth == 0) {
    294       if (ctx->Transform.MatrixMode == GL_TEXTURE) {
    295          _mesa_error(ctx,  GL_STACK_UNDERFLOW,
    296                      "glPopMatrix(mode=GL_TEXTURE, unit=%d)",
    297                       ctx->Texture.CurrentUnit);
    298       }
    299       else {
    300          _mesa_error(ctx,  GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)",
    301                      _mesa_enum_to_string(ctx->Transform.MatrixMode));
    302       }
    303       return;
    304    }
    305    stack->Depth--;
    306    stack->Top = &(stack->Stack[stack->Depth]);
    307    ctx->NewState |= stack->DirtyFlag;
    308 }
    309 
    310 
    311 /**
    312  * Replace the current matrix with the identity matrix.
    313  *
    314  * \sa glLoadIdentity().
    315  *
    316  * Flushes the vertices and calls _math_matrix_set_identity() with the
    317  * top-most matrix in the current stack.
    318  * Marks __struct gl_contextRec::NewState with the stack dirty flag.
    319  */
    320 void GLAPIENTRY
    321 _mesa_LoadIdentity( void )
    322 {
    323    GET_CURRENT_CONTEXT(ctx);
    324 
    325    FLUSH_VERTICES(ctx, 0);
    326 
    327    if (MESA_VERBOSE & VERBOSE_API)
    328       _mesa_debug(ctx, "glLoadIdentity()\n");
    329 
    330    _math_matrix_set_identity( ctx->CurrentStack->Top );
    331    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    332 }
    333 
    334 
    335 /**
    336  * Replace the current matrix with a given matrix.
    337  *
    338  * \param m matrix.
    339  *
    340  * \sa glLoadMatrixf().
    341  *
    342  * Flushes the vertices and calls _math_matrix_loadf() with the top-most
    343  * matrix in the current stack and the given matrix.
    344  * Marks __struct gl_contextRec::NewState with the dirty stack flag.
    345  */
    346 void GLAPIENTRY
    347 _mesa_LoadMatrixf( const GLfloat *m )
    348 {
    349    GET_CURRENT_CONTEXT(ctx);
    350    if (!m) return;
    351    if (MESA_VERBOSE & VERBOSE_API)
    352       _mesa_debug(ctx,
    353           "glLoadMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
    354           m[0], m[4], m[8], m[12],
    355           m[1], m[5], m[9], m[13],
    356           m[2], m[6], m[10], m[14],
    357           m[3], m[7], m[11], m[15]);
    358 
    359    if (memcmp(m, ctx->CurrentStack->Top->m, 16 * sizeof(GLfloat)) != 0) {
    360       FLUSH_VERTICES(ctx, 0);
    361       _math_matrix_loadf( ctx->CurrentStack->Top, m );
    362       ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    363    }
    364 }
    365 
    366 
    367 /**
    368  * Multiply the current matrix with a given matrix.
    369  *
    370  * \param m matrix.
    371  *
    372  * \sa glMultMatrixf().
    373  *
    374  * Flushes the vertices and calls _math_matrix_mul_floats() with the top-most
    375  * matrix in the current stack and the given matrix. Marks
    376  * __struct gl_contextRec::NewState with the dirty stack flag.
    377  */
    378 void GLAPIENTRY
    379 _mesa_MultMatrixf( const GLfloat *m )
    380 {
    381    GET_CURRENT_CONTEXT(ctx);
    382    if (!m) return;
    383    if (MESA_VERBOSE & VERBOSE_API)
    384       _mesa_debug(ctx,
    385           "glMultMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
    386           m[0], m[4], m[8], m[12],
    387           m[1], m[5], m[9], m[13],
    388           m[2], m[6], m[10], m[14],
    389           m[3], m[7], m[11], m[15]);
    390 
    391    FLUSH_VERTICES(ctx, 0);
    392    _math_matrix_mul_floats( ctx->CurrentStack->Top, m );
    393    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    394 }
    395 
    396 
    397 /**
    398  * Multiply the current matrix with a rotation matrix.
    399  *
    400  * \param angle angle of rotation, in degrees.
    401  * \param x rotation vector x coordinate.
    402  * \param y rotation vector y coordinate.
    403  * \param z rotation vector z coordinate.
    404  *
    405  * \sa glRotatef().
    406  *
    407  * Flushes the vertices and calls _math_matrix_rotate() with the top-most
    408  * matrix in the current stack and the given parameters. Marks
    409  * __struct gl_contextRec::NewState with the dirty stack flag.
    410  */
    411 void GLAPIENTRY
    412 _mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
    413 {
    414    GET_CURRENT_CONTEXT(ctx);
    415 
    416    FLUSH_VERTICES(ctx, 0);
    417    if (angle != 0.0F) {
    418       _math_matrix_rotate( ctx->CurrentStack->Top, angle, x, y, z);
    419       ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    420    }
    421 }
    422 
    423 
    424 /**
    425  * Multiply the current matrix with a general scaling matrix.
    426  *
    427  * \param x x axis scale factor.
    428  * \param y y axis scale factor.
    429  * \param z z axis scale factor.
    430  *
    431  * \sa glScalef().
    432  *
    433  * Flushes the vertices and calls _math_matrix_scale() with the top-most
    434  * matrix in the current stack and the given parameters. Marks
    435  * __struct gl_contextRec::NewState with the dirty stack flag.
    436  */
    437 void GLAPIENTRY
    438 _mesa_Scalef( GLfloat x, GLfloat y, GLfloat z )
    439 {
    440    GET_CURRENT_CONTEXT(ctx);
    441 
    442    FLUSH_VERTICES(ctx, 0);
    443    _math_matrix_scale( ctx->CurrentStack->Top, x, y, z);
    444    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    445 }
    446 
    447 
    448 /**
    449  * Multiply the current matrix with a translation matrix.
    450  *
    451  * \param x translation vector x coordinate.
    452  * \param y translation vector y coordinate.
    453  * \param z translation vector z coordinate.
    454  *
    455  * \sa glTranslatef().
    456  *
    457  * Flushes the vertices and calls _math_matrix_translate() with the top-most
    458  * matrix in the current stack and the given parameters. Marks
    459  * __struct gl_contextRec::NewState with the dirty stack flag.
    460  */
    461 void GLAPIENTRY
    462 _mesa_Translatef( GLfloat x, GLfloat y, GLfloat z )
    463 {
    464    GET_CURRENT_CONTEXT(ctx);
    465 
    466    FLUSH_VERTICES(ctx, 0);
    467    _math_matrix_translate( ctx->CurrentStack->Top, x, y, z);
    468    ctx->NewState |= ctx->CurrentStack->DirtyFlag;
    469 }
    470 
    471 
    472 void GLAPIENTRY
    473 _mesa_LoadMatrixd( const GLdouble *m )
    474 {
    475    GLint i;
    476    GLfloat f[16];
    477    if (!m) return;
    478    for (i = 0; i < 16; i++)
    479       f[i] = (GLfloat) m[i];
    480    _mesa_LoadMatrixf(f);
    481 }
    482 
    483 void GLAPIENTRY
    484 _mesa_MultMatrixd( const GLdouble *m )
    485 {
    486    GLint i;
    487    GLfloat f[16];
    488    if (!m) return;
    489    for (i = 0; i < 16; i++)
    490       f[i] = (GLfloat) m[i];
    491    _mesa_MultMatrixf( f );
    492 }
    493 
    494 
    495 void GLAPIENTRY
    496 _mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z )
    497 {
    498    _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z);
    499 }
    500 
    501 
    502 void GLAPIENTRY
    503 _mesa_Scaled( GLdouble x, GLdouble y, GLdouble z )
    504 {
    505    _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z);
    506 }
    507 
    508 
    509 void GLAPIENTRY
    510 _mesa_Translated( GLdouble x, GLdouble y, GLdouble z )
    511 {
    512    _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z);
    513 }
    514 
    515 
    516 void GLAPIENTRY
    517 _mesa_LoadTransposeMatrixf( const GLfloat *m )
    518 {
    519    GLfloat tm[16];
    520    if (!m) return;
    521    _math_transposef(tm, m);
    522    _mesa_LoadMatrixf(tm);
    523 }
    524 
    525 
    526 void GLAPIENTRY
    527 _mesa_LoadTransposeMatrixd( const GLdouble *m )
    528 {
    529    GLfloat tm[16];
    530    if (!m) return;
    531    _math_transposefd(tm, m);
    532    _mesa_LoadMatrixf(tm);
    533 }
    534 
    535 
    536 void GLAPIENTRY
    537 _mesa_MultTransposeMatrixf( const GLfloat *m )
    538 {
    539    GLfloat tm[16];
    540    if (!m) return;
    541    _math_transposef(tm, m);
    542    _mesa_MultMatrixf(tm);
    543 }
    544 
    545 
    546 void GLAPIENTRY
    547 _mesa_MultTransposeMatrixd( const GLdouble *m )
    548 {
    549    GLfloat tm[16];
    550    if (!m) return;
    551    _math_transposefd(tm, m);
    552    _mesa_MultMatrixf(tm);
    553 }
    554 
    555 
    556 
    557 /**********************************************************************/
    558 /** \name State management */
    559 /*@{*/
    560 
    561 
    562 /**
    563  * Update the projection matrix stack.
    564  *
    565  * \param ctx GL context.
    566  *
    567  * Calls _math_matrix_analyse() with the top-matrix of the projection matrix
    568  * stack, and recomputes user clip positions if necessary.
    569  *
    570  * \note This routine references __struct gl_contextRec::Tranform attribute
    571  * values to compute userclip positions in clip space, but is only called on
    572  * _NEW_PROJECTION.  The _mesa_ClipPlane() function keeps these values up to
    573  * date across changes to the __struct gl_contextRec::Transform attributes.
    574  */
    575 static void
    576 update_projection( struct gl_context *ctx )
    577 {
    578    GLbitfield mask;
    579 
    580    _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );
    581 
    582    /* Recompute clip plane positions in clipspace.  This is also done
    583     * in _mesa_ClipPlane().
    584     */
    585    mask = ctx->Transform.ClipPlanesEnabled;
    586    while (mask) {
    587       const int p = u_bit_scan(&mask);
    588 
    589       _mesa_transform_vector( ctx->Transform._ClipUserPlane[p],
    590                               ctx->Transform.EyeUserPlane[p],
    591                               ctx->ProjectionMatrixStack.Top->inv );
    592    }
    593 }
    594 
    595 
    596 /**
    597  * Calculate the combined modelview-projection matrix.
    598  *
    599  * \param ctx GL context.
    600  *
    601  * Multiplies the top matrices of the projection and model view stacks into
    602  * __struct gl_contextRec::_ModelProjectMatrix via _math_matrix_mul_matrix()
    603  * and analyzes the resulting matrix via _math_matrix_analyse().
    604  */
    605 static void
    606 calculate_model_project_matrix( struct gl_context *ctx )
    607 {
    608    _math_matrix_mul_matrix( &ctx->_ModelProjectMatrix,
    609                             ctx->ProjectionMatrixStack.Top,
    610                             ctx->ModelviewMatrixStack.Top );
    611 
    612    _math_matrix_analyse( &ctx->_ModelProjectMatrix );
    613 }
    614 
    615 
    616 /**
    617  * Updates the combined modelview-projection matrix.
    618  *
    619  * \param ctx GL context.
    620  * \param new_state new state bit mask.
    621  *
    622  * If there is a new model view matrix then analyzes it. If there is a new
    623  * projection matrix, updates it. Finally calls
    624  * calculate_model_project_matrix() to recalculate the modelview-projection
    625  * matrix.
    626  */
    627 void _mesa_update_modelview_project( struct gl_context *ctx, GLuint new_state )
    628 {
    629    if (new_state & _NEW_MODELVIEW)
    630       _math_matrix_analyse( ctx->ModelviewMatrixStack.Top );
    631 
    632    if (new_state & _NEW_PROJECTION)
    633       update_projection( ctx );
    634 
    635    /* Keep ModelviewProject up to date always to allow tnl
    636     * implementations that go model->clip even when eye is required.
    637     */
    638    calculate_model_project_matrix(ctx);
    639 }
    640 
    641 /*@}*/
    642 
    643 
    644 /**********************************************************************/
    645 /** Matrix stack initialization */
    646 /*@{*/
    647 
    648 
    649 /**
    650  * Initialize a matrix stack.
    651  *
    652  * \param stack matrix stack.
    653  * \param maxDepth maximum stack depth.
    654  * \param dirtyFlag dirty flag.
    655  *
    656  * Allocates an array of \p maxDepth elements for the matrix stack and calls
    657  * _math_matrix_ctr() for each element to initialize it.
    658  */
    659 static void
    660 init_matrix_stack( struct gl_matrix_stack *stack,
    661                    GLuint maxDepth, GLuint dirtyFlag )
    662 {
    663    GLuint i;
    664 
    665    stack->Depth = 0;
    666    stack->MaxDepth = maxDepth;
    667    stack->DirtyFlag = dirtyFlag;
    668    /* The stack will be dynamically resized at glPushMatrix() time */
    669    stack->Stack = calloc(1, sizeof(GLmatrix));
    670    stack->StackSize = 1;
    671    for (i = 0; i < stack->StackSize; i++) {
    672       _math_matrix_ctr(&stack->Stack[i]);
    673    }
    674    stack->Top = stack->Stack;
    675 }
    676 
    677 /**
    678  * Free matrix stack.
    679  *
    680  * \param stack matrix stack.
    681  *
    682  * Calls _math_matrix_dtr() for each element of the matrix stack and
    683  * frees the array.
    684  */
    685 static void
    686 free_matrix_stack( struct gl_matrix_stack *stack )
    687 {
    688    GLuint i;
    689    for (i = 0; i < stack->StackSize; i++) {
    690       _math_matrix_dtr(&stack->Stack[i]);
    691    }
    692    free(stack->Stack);
    693    stack->Stack = stack->Top = NULL;
    694    stack->StackSize = 0;
    695 }
    696 
    697 /*@}*/
    698 
    699 
    700 /**********************************************************************/
    701 /** \name Initialization */
    702 /*@{*/
    703 
    704 
    705 /**
    706  * Initialize the context matrix data.
    707  *
    708  * \param ctx GL context.
    709  *
    710  * Initializes each of the matrix stacks and the combined modelview-projection
    711  * matrix.
    712  */
    713 void _mesa_init_matrix( struct gl_context * ctx )
    714 {
    715    GLuint i;
    716 
    717    /* Initialize matrix stacks */
    718    init_matrix_stack(&ctx->ModelviewMatrixStack, MAX_MODELVIEW_STACK_DEPTH,
    719                      _NEW_MODELVIEW);
    720    init_matrix_stack(&ctx->ProjectionMatrixStack, MAX_PROJECTION_STACK_DEPTH,
    721                      _NEW_PROJECTION);
    722    for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++)
    723       init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH,
    724                         _NEW_TEXTURE_MATRIX);
    725    for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++)
    726       init_matrix_stack(&ctx->ProgramMatrixStack[i],
    727 		        MAX_PROGRAM_MATRIX_STACK_DEPTH, _NEW_TRACK_MATRIX);
    728    ctx->CurrentStack = &ctx->ModelviewMatrixStack;
    729 
    730    /* Init combined Modelview*Projection matrix */
    731    _math_matrix_ctr( &ctx->_ModelProjectMatrix );
    732 }
    733 
    734 
    735 /**
    736  * Free the context matrix data.
    737  *
    738  * \param ctx GL context.
    739  *
    740  * Frees each of the matrix stacks and the combined modelview-projection
    741  * matrix.
    742  */
    743 void _mesa_free_matrix_data( struct gl_context *ctx )
    744 {
    745    GLuint i;
    746 
    747    free_matrix_stack(&ctx->ModelviewMatrixStack);
    748    free_matrix_stack(&ctx->ProjectionMatrixStack);
    749    for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++)
    750       free_matrix_stack(&ctx->TextureMatrixStack[i]);
    751    for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++)
    752       free_matrix_stack(&ctx->ProgramMatrixStack[i]);
    753    /* combined Modelview*Projection matrix */
    754    _math_matrix_dtr( &ctx->_ModelProjectMatrix );
    755 
    756 }
    757 
    758 
    759 /**
    760  * Initialize the context transform attribute group.
    761  *
    762  * \param ctx GL context.
    763  *
    764  * \todo Move this to a new file with other 'transform' routines.
    765  */
    766 void _mesa_init_transform( struct gl_context *ctx )
    767 {
    768    GLuint i;
    769 
    770    /* Transformation group */
    771    ctx->Transform.MatrixMode = GL_MODELVIEW;
    772    ctx->Transform.Normalize = GL_FALSE;
    773    ctx->Transform.RescaleNormals = GL_FALSE;
    774    ctx->Transform.RasterPositionUnclipped = GL_FALSE;
    775    for (i=0;i<ctx->Const.MaxClipPlanes;i++) {
    776       ASSIGN_4V( ctx->Transform.EyeUserPlane[i], 0.0, 0.0, 0.0, 0.0 );
    777    }
    778    ctx->Transform.ClipPlanesEnabled = 0;
    779 }
    780 
    781 
    782 /*@}*/
    783