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