matrix.c revision 75a8383e8d9940bd933dea1ef3b33d8321a6a723
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.3 4 * 5 * Copyright (C) 1999-2005 Brian Paul 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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * \file matrix.c 28 * Matrix operations. 29 * 30 * \note 31 * -# 4x4 transformation matrices are stored in memory in column major order. 32 * -# Points/vertices are to be thought of as column vectors. 33 * -# Transformation of a point p by a matrix M is: p' = M * p 34 */ 35 36 37#include "glheader.h" 38#include "imports.h" 39#include "context.h" 40#include "enums.h" 41#include "macros.h" 42#include "matrix.h" 43#include "mtypes.h" 44#include "math/m_matrix.h" 45#include "math/m_xform.h" 46 47 48/** 49 * Apply a perspective projection matrix. 50 * 51 * \param left left clipping plane coordinate. 52 * \param right right clipping plane coordinate. 53 * \param bottom bottom clipping plane coordinate. 54 * \param top top clipping plane coordinate. 55 * \param nearval distance to the near clipping plane. 56 * \param farval distance to the far clipping plane. 57 * 58 * \sa glFrustum(). 59 * 60 * Flushes vertices and validates parameters. Calls _math_matrix_frustum() with 61 * the top matrix of the current matrix stack and sets 62 * __GLcontextRec::NewState. 63 */ 64void GLAPIENTRY 65_mesa_Frustum( GLdouble left, GLdouble right, 66 GLdouble bottom, GLdouble top, 67 GLdouble nearval, GLdouble farval ) 68{ 69 GET_CURRENT_CONTEXT(ctx); 70 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 71 72 if (nearval <= 0.0 || 73 farval <= 0.0 || 74 nearval == farval || 75 left == right || 76 top == bottom) 77 { 78 _mesa_error( ctx, GL_INVALID_VALUE, "glFrustum" ); 79 return; 80 } 81 82 _math_matrix_frustum( ctx->CurrentStack->Top, 83 (GLfloat) left, (GLfloat) right, 84 (GLfloat) bottom, (GLfloat) top, 85 (GLfloat) nearval, (GLfloat) farval ); 86 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 87} 88 89 90/** 91 * Apply an orthographic projection matrix. 92 * 93 * \param left left clipping plane coordinate. 94 * \param right right clipping plane coordinate. 95 * \param bottom bottom clipping plane coordinate. 96 * \param top top clipping plane coordinate. 97 * \param nearval distance to the near clipping plane. 98 * \param farval distance to the far clipping plane. 99 * 100 * \sa glOrtho(). 101 * 102 * Flushes vertices and validates parameters. Calls _math_matrix_ortho() with 103 * the top matrix of the current matrix stack and sets 104 * __GLcontextRec::NewState. 105 */ 106void GLAPIENTRY 107_mesa_Ortho( GLdouble left, GLdouble right, 108 GLdouble bottom, GLdouble top, 109 GLdouble nearval, GLdouble farval ) 110{ 111 GET_CURRENT_CONTEXT(ctx); 112 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 113 114 if (MESA_VERBOSE & VERBOSE_API) 115 _mesa_debug(ctx, "glOrtho(%f, %f, %f, %f, %f, %f)\n", 116 left, right, bottom, top, nearval, farval); 117 118 if (left == right || 119 bottom == top || 120 nearval == farval) 121 { 122 _mesa_error( ctx, GL_INVALID_VALUE, "glOrtho" ); 123 return; 124 } 125 126 _math_matrix_ortho( ctx->CurrentStack->Top, 127 (GLfloat) left, (GLfloat) right, 128 (GLfloat) bottom, (GLfloat) top, 129 (GLfloat) nearval, (GLfloat) farval ); 130 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 131} 132 133 134/** 135 * Set the current matrix stack. 136 * 137 * \param mode matrix stack. 138 * 139 * \sa glMatrixMode(). 140 * 141 * Flushes the vertices, validates the parameter and updates 142 * __GLcontextRec::CurrentStack and gl_transform_attrib::MatrixMode with the 143 * specified matrix stack. 144 */ 145void GLAPIENTRY 146_mesa_MatrixMode( GLenum mode ) 147{ 148 GET_CURRENT_CONTEXT(ctx); 149 ASSERT_OUTSIDE_BEGIN_END(ctx); 150 151 if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE) 152 return; 153 FLUSH_VERTICES(ctx, _NEW_TRANSFORM); 154 155 switch (mode) { 156 case GL_MODELVIEW: 157 ctx->CurrentStack = &ctx->ModelviewMatrixStack; 158 break; 159 case GL_PROJECTION: 160 ctx->CurrentStack = &ctx->ProjectionMatrixStack; 161 break; 162 case GL_TEXTURE: 163 ctx->CurrentStack = &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit]; 164 break; 165 case GL_COLOR: 166 ctx->CurrentStack = &ctx->ColorMatrixStack; 167 break; 168 case GL_MATRIX0_NV: 169 case GL_MATRIX1_NV: 170 case GL_MATRIX2_NV: 171 case GL_MATRIX3_NV: 172 case GL_MATRIX4_NV: 173 case GL_MATRIX5_NV: 174 case GL_MATRIX6_NV: 175 case GL_MATRIX7_NV: 176 if (ctx->Extensions.NV_vertex_program) { 177 ctx->CurrentStack = &ctx->ProgramMatrixStack[mode - GL_MATRIX0_NV]; 178 } 179 else { 180 _mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" ); 181 return; 182 } 183 break; 184 case GL_MATRIX0_ARB: 185 case GL_MATRIX1_ARB: 186 case GL_MATRIX2_ARB: 187 case GL_MATRIX3_ARB: 188 case GL_MATRIX4_ARB: 189 case GL_MATRIX5_ARB: 190 case GL_MATRIX6_ARB: 191 case GL_MATRIX7_ARB: 192 if (ctx->Extensions.ARB_vertex_program || 193 ctx->Extensions.ARB_fragment_program) { 194 const GLuint m = mode - GL_MATRIX0_ARB; 195 if (m > ctx->Const.MaxProgramMatrices) { 196 _mesa_error(ctx, GL_INVALID_ENUM, 197 "glMatrixMode(GL_MATRIX%d_ARB)", m); 198 return; 199 } 200 ctx->CurrentStack = &ctx->ProgramMatrixStack[m]; 201 } 202 else { 203 _mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" ); 204 return; 205 } 206 break; 207 default: 208 _mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" ); 209 return; 210 } 211 212 ctx->Transform.MatrixMode = mode; 213} 214 215 216/** 217 * Push the current matrix stack. 218 * 219 * \sa glPushMatrix(). 220 * 221 * Verifies the current matrix stack is not full, and duplicates the top-most 222 * matrix in the stack. Marks __GLcontextRec::NewState with the stack dirty 223 * flag. 224 */ 225void GLAPIENTRY 226_mesa_PushMatrix( void ) 227{ 228 GET_CURRENT_CONTEXT(ctx); 229 struct matrix_stack *stack = ctx->CurrentStack; 230 ASSERT_OUTSIDE_BEGIN_END(ctx); 231 232 if (MESA_VERBOSE&VERBOSE_API) 233 _mesa_debug(ctx, "glPushMatrix %s\n", 234 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode)); 235 236 if (stack->Depth + 1 >= stack->MaxDepth) { 237 if (ctx->Transform.MatrixMode == GL_TEXTURE) { 238 _mesa_error(ctx, GL_STACK_OVERFLOW, 239 "glPushMatrix(mode=GL_TEXTURE, unit=%d)", 240 ctx->Texture.CurrentUnit); 241 } 242 else { 243 _mesa_error(ctx, GL_STACK_OVERFLOW, "glPushMatrix(mode=%s)", 244 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode)); 245 } 246 return; 247 } 248 _math_matrix_copy( &stack->Stack[stack->Depth + 1], 249 &stack->Stack[stack->Depth] ); 250 stack->Depth++; 251 stack->Top = &(stack->Stack[stack->Depth]); 252 ctx->NewState |= stack->DirtyFlag; 253} 254 255 256/** 257 * Pop the current matrix stack. 258 * 259 * \sa glPopMatrix(). 260 * 261 * Flushes the vertices, verifies the current matrix stack is not empty, and 262 * moves the stack head down. Marks __GLcontextRec::NewState with the dirty 263 * stack flag. 264 */ 265void GLAPIENTRY 266_mesa_PopMatrix( void ) 267{ 268 GET_CURRENT_CONTEXT(ctx); 269 struct matrix_stack *stack = ctx->CurrentStack; 270 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 271 272 if (MESA_VERBOSE&VERBOSE_API) 273 _mesa_debug(ctx, "glPopMatrix %s\n", 274 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode)); 275 276 if (stack->Depth == 0) { 277 if (ctx->Transform.MatrixMode == GL_TEXTURE) { 278 _mesa_error(ctx, GL_STACK_UNDERFLOW, 279 "glPopMatrix(mode=GL_TEXTURE, unit=%d)", 280 ctx->Texture.CurrentUnit); 281 } 282 else { 283 _mesa_error(ctx, GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)", 284 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode)); 285 } 286 return; 287 } 288 stack->Depth--; 289 stack->Top = &(stack->Stack[stack->Depth]); 290 ctx->NewState |= stack->DirtyFlag; 291} 292 293 294/** 295 * Replace the current matrix with the identity matrix. 296 * 297 * \sa glLoadIdentity(). 298 * 299 * Flushes the vertices and calls _math_matrix_set_identity() with the top-most 300 * matrix in the current stack. Marks __GLcontextRec::NewState with the stack 301 * dirty flag. 302 */ 303void GLAPIENTRY 304_mesa_LoadIdentity( void ) 305{ 306 GET_CURRENT_CONTEXT(ctx); 307 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 308 309 if (MESA_VERBOSE & VERBOSE_API) 310 _mesa_debug(ctx, "glLoadIdentity()"); 311 312 _math_matrix_set_identity( ctx->CurrentStack->Top ); 313 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 314} 315 316 317/** 318 * Replace the current matrix with a given matrix. 319 * 320 * \param m matrix. 321 * 322 * \sa glLoadMatrixf(). 323 * 324 * Flushes the vertices and calls _math_matrix_loadf() with the top-most matrix 325 * in the current stack and the given matrix. Marks __GLcontextRec::NewState 326 * with the dirty stack flag. 327 */ 328void GLAPIENTRY 329_mesa_LoadMatrixf( const GLfloat *m ) 330{ 331 GET_CURRENT_CONTEXT(ctx); 332 if (!m) return; 333 if (MESA_VERBOSE & VERBOSE_API) 334 _mesa_debug(ctx, 335 "glLoadMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 336 m[0], m[4], m[8], m[12], 337 m[1], m[5], m[9], m[13], 338 m[2], m[6], m[10], m[14], 339 m[3], m[7], m[11], m[15]); 340 341 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 342 _math_matrix_loadf( ctx->CurrentStack->Top, m ); 343 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 344} 345 346 347/** 348 * Multiply the current matrix with a given matrix. 349 * 350 * \param m matrix. 351 * 352 * \sa glMultMatrixf(). 353 * 354 * Flushes the vertices and calls _math_matrix_mul_floats() with the top-most 355 * matrix in the current stack and the given matrix. Marks 356 * __GLcontextRec::NewState with the dirty stack flag. 357 */ 358void GLAPIENTRY 359_mesa_MultMatrixf( const GLfloat *m ) 360{ 361 GET_CURRENT_CONTEXT(ctx); 362 if (!m) return; 363 if (MESA_VERBOSE & VERBOSE_API) 364 _mesa_debug(ctx, 365 "glMultMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 366 m[0], m[4], m[8], m[12], 367 m[1], m[5], m[9], m[13], 368 m[2], m[6], m[10], m[14], 369 m[3], m[7], m[11], m[15]); 370 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 371 _math_matrix_mul_floats( ctx->CurrentStack->Top, m ); 372 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 373} 374 375 376/** 377 * Multiply the current matrix with a rotation matrix. 378 * 379 * \param angle angle of rotation, in degrees. 380 * \param x rotation vector x coordinate. 381 * \param y rotation vector y coordinate. 382 * \param z rotation vector z coordinate. 383 * 384 * \sa glRotatef(). 385 * 386 * Flushes the vertices and calls _math_matrix_rotate() with the top-most 387 * matrix in the current stack and the given parameters. Marks 388 * __GLcontextRec::NewState with the dirty stack flag. 389 */ 390void GLAPIENTRY 391_mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) 392{ 393 GET_CURRENT_CONTEXT(ctx); 394 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 395 if (angle != 0.0F) { 396 _math_matrix_rotate( ctx->CurrentStack->Top, angle, x, y, z); 397 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 398 } 399} 400 401 402/** 403 * Multiply the current matrix with a general scaling matrix. 404 * 405 * \param x x axis scale factor. 406 * \param y y axis scale factor. 407 * \param z z axis scale factor. 408 * 409 * \sa glScalef(). 410 * 411 * Flushes the vertices and calls _math_matrix_scale() with the top-most 412 * matrix in the current stack and the given parameters. Marks 413 * __GLcontextRec::NewState with the dirty stack flag. 414 */ 415void GLAPIENTRY 416_mesa_Scalef( GLfloat x, GLfloat y, GLfloat z ) 417{ 418 GET_CURRENT_CONTEXT(ctx); 419 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 420 _math_matrix_scale( ctx->CurrentStack->Top, x, y, z); 421 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 422} 423 424 425/** 426 * Multiply the current matrix with a general scaling matrix. 427 * 428 * \param x translation vector x coordinate. 429 * \param y translation vector y coordinate. 430 * \param z translation vector z coordinate. 431 * 432 * \sa glTranslatef(). 433 * 434 * Flushes the vertices and calls _math_matrix_translate() with the top-most 435 * matrix in the current stack and the given parameters. Marks 436 * __GLcontextRec::NewState with the dirty stack flag. 437 */ 438void GLAPIENTRY 439_mesa_Translatef( GLfloat x, GLfloat y, GLfloat z ) 440{ 441 GET_CURRENT_CONTEXT(ctx); 442 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 443 _math_matrix_translate( ctx->CurrentStack->Top, x, y, z); 444 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 445} 446 447 448#if _HAVE_FULL_GL 449void GLAPIENTRY 450_mesa_LoadMatrixd( const GLdouble *m ) 451{ 452 GLint i; 453 GLfloat f[16]; 454 if (!m) return; 455 for (i = 0; i < 16; i++) 456 f[i] = (GLfloat) m[i]; 457 _mesa_LoadMatrixf(f); 458} 459 460void GLAPIENTRY 461_mesa_MultMatrixd( const GLdouble *m ) 462{ 463 GLint i; 464 GLfloat f[16]; 465 if (!m) return; 466 for (i = 0; i < 16; i++) 467 f[i] = (GLfloat) m[i]; 468 _mesa_MultMatrixf( f ); 469} 470 471 472void GLAPIENTRY 473_mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) 474{ 475 _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z); 476} 477 478 479void GLAPIENTRY 480_mesa_Scaled( GLdouble x, GLdouble y, GLdouble z ) 481{ 482 _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z); 483} 484 485 486void GLAPIENTRY 487_mesa_Translated( GLdouble x, GLdouble y, GLdouble z ) 488{ 489 _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z); 490} 491#endif 492 493 494#if _HAVE_FULL_GL 495void GLAPIENTRY 496_mesa_LoadTransposeMatrixfARB( const GLfloat *m ) 497{ 498 GLfloat tm[16]; 499 if (!m) return; 500 _math_transposef(tm, m); 501 _mesa_LoadMatrixf(tm); 502} 503 504 505void GLAPIENTRY 506_mesa_LoadTransposeMatrixdARB( const GLdouble *m ) 507{ 508 GLfloat tm[16]; 509 if (!m) return; 510 _math_transposefd(tm, m); 511 _mesa_LoadMatrixf(tm); 512} 513 514 515void GLAPIENTRY 516_mesa_MultTransposeMatrixfARB( const GLfloat *m ) 517{ 518 GLfloat tm[16]; 519 if (!m) return; 520 _math_transposef(tm, m); 521 _mesa_MultMatrixf(tm); 522} 523 524 525void GLAPIENTRY 526_mesa_MultTransposeMatrixdARB( const GLdouble *m ) 527{ 528 GLfloat tm[16]; 529 if (!m) return; 530 _math_transposefd(tm, m); 531 _mesa_MultMatrixf(tm); 532} 533#endif 534 535/** 536 * Set the viewport. 537 * 538 * \param x, y coordinates of the lower-left corner of the viewport rectangle. 539 * \param width width of the viewport rectangle. 540 * \param height height of the viewport rectangle. 541 * 542 * \sa Called via glViewport() or display list execution. 543 * 544 * Flushes the vertices and calls _mesa_set_viewport() with the given 545 * parameters. 546 */ 547void GLAPIENTRY 548_mesa_Viewport( GLint x, GLint y, GLsizei width, GLsizei height ) 549{ 550 GET_CURRENT_CONTEXT(ctx); 551 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 552 _mesa_set_viewport(ctx, x, y, width, height); 553} 554 555 556/** 557 * Set new viewport parameters and update derived state (the _WindowMap 558 * matrix). Usually called from _mesa_Viewport(). 559 * 560 * \param ctx GL context. 561 * \param x, y coordinates of the lower left corner of the viewport rectangle. 562 * \param width width of the viewport rectangle. 563 * \param height height of the viewport rectangle. 564 */ 565void 566_mesa_set_viewport( GLcontext *ctx, GLint x, GLint y, 567 GLsizei width, GLsizei height ) 568{ 569 if (MESA_VERBOSE & VERBOSE_API) 570 _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height); 571 572 if (width < 0 || height < 0) { 573 _mesa_error( ctx, GL_INVALID_VALUE, 574 "glViewport(%d, %d, %d, %d)", x, y, width, height ); 575 return; 576 } 577 578 /* clamp width and height to the implementation dependent range */ 579 width = CLAMP(width, 1, ctx->Const.MaxViewportWidth); 580 height = CLAMP(height, 1, ctx->Const.MaxViewportHeight); 581 582 ctx->Viewport.X = x; 583 ctx->Viewport.Width = width; 584 ctx->Viewport.Y = y; 585 ctx->Viewport.Height = height; 586 ctx->NewState |= _NEW_VIEWPORT; 587 588#if 1 589 /* XXX remove this someday. Currently the DRI drivers rely on 590 * the WindowMap matrix being up to date in the driver's Viewport 591 * and DepthRange functions. 592 */ 593 _math_matrix_viewport(&ctx->Viewport._WindowMap, 594 ctx->Viewport.X, ctx->Viewport.Y, 595 ctx->Viewport.Width, ctx->Viewport.Height, 596 ctx->Viewport.Near, ctx->Viewport.Far, 597 ctx->DrawBuffer->_DepthMaxF); 598#endif 599 600 if (ctx->Driver.Viewport) { 601 /* Many drivers will use this call to check for window size changes 602 * and reallocate the z/stencil/accum/etc buffers if needed. 603 */ 604 (*ctx->Driver.Viewport)( ctx, x, y, width, height ); 605 } 606} 607 608 609#if _HAVE_FULL_GL 610/** 611 * Called by glDepthRange 612 * 613 * \param nearval specifies the Z buffer value which should correspond to 614 * the near clip plane 615 * \param farval specifies the Z buffer value which should correspond to 616 * the far clip plane 617 */ 618void GLAPIENTRY 619_mesa_DepthRange( GLclampd nearval, GLclampd farval ) 620{ 621 GET_CURRENT_CONTEXT(ctx); 622 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 623 624 if (MESA_VERBOSE&VERBOSE_API) 625 _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval); 626 627 ctx->Viewport.Near = (GLfloat) CLAMP( nearval, 0.0, 1.0 ); 628 ctx->Viewport.Far = (GLfloat) CLAMP( farval, 0.0, 1.0 ); 629 ctx->NewState |= _NEW_VIEWPORT; 630 631#if 1 632 /* XXX remove this someday. Currently the DRI drivers rely on 633 * the WindowMap matrix being up to date in the driver's Viewport 634 * and DepthRange functions. 635 */ 636 _math_matrix_viewport(&ctx->Viewport._WindowMap, 637 ctx->Viewport.X, ctx->Viewport.Y, 638 ctx->Viewport.Width, ctx->Viewport.Height, 639 ctx->Viewport.Near, ctx->Viewport.Far, 640 ctx->DrawBuffer->_DepthMaxF); 641#endif 642 643 if (ctx->Driver.DepthRange) { 644 (*ctx->Driver.DepthRange)( ctx, nearval, farval ); 645 } 646} 647#endif 648 649 650 651/**********************************************************************/ 652/** \name State management */ 653/*@{*/ 654 655 656/** 657 * Update the projection matrix stack. 658 * 659 * \param ctx GL context. 660 * 661 * Calls _math_matrix_analyse() with the top-matrix of the projection matrix 662 * stack, and recomputes user clip positions if necessary. 663 * 664 * \note This routine references __GLcontextRec::Tranform attribute values to 665 * compute userclip positions in clip space, but is only called on 666 * _NEW_PROJECTION. The _mesa_ClipPlane() function keeps these values up to 667 * date across changes to the __GLcontextRec::Transform attributes. 668 */ 669static void 670update_projection( GLcontext *ctx ) 671{ 672 _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); 673 674#if FEATURE_userclip 675 /* Recompute clip plane positions in clipspace. This is also done 676 * in _mesa_ClipPlane(). 677 */ 678 if (ctx->Transform.ClipPlanesEnabled) { 679 GLuint p; 680 for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { 681 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { 682 _mesa_transform_vector( ctx->Transform._ClipUserPlane[p], 683 ctx->Transform.EyeUserPlane[p], 684 ctx->ProjectionMatrixStack.Top->inv ); 685 } 686 } 687 } 688#endif 689} 690 691 692/** 693 * Calculate the combined modelview-projection matrix. 694 * 695 * \param ctx GL context. 696 * 697 * Multiplies the top matrices of the projection and model view stacks into 698 * __GLcontextRec::_ModelProjectMatrix via _math_matrix_mul_matrix() and 699 * analyzes the resulting matrix via _math_matrix_analyse(). 700 */ 701static void 702calculate_model_project_matrix( GLcontext *ctx ) 703{ 704 _math_matrix_mul_matrix( &ctx->_ModelProjectMatrix, 705 ctx->ProjectionMatrixStack.Top, 706 ctx->ModelviewMatrixStack.Top ); 707 708 _math_matrix_analyse( &ctx->_ModelProjectMatrix ); 709} 710 711 712/** 713 * Updates the combined modelview-projection matrix. 714 * 715 * \param ctx GL context. 716 * \param new_state new state bit mask. 717 * 718 * If there is a new model view matrix then analyzes it. If there is a new 719 * projection matrix, updates it. Finally calls 720 * calculate_model_project_matrix() to recalculate the modelview-projection 721 * matrix. 722 */ 723void _mesa_update_modelview_project( GLcontext *ctx, GLuint new_state ) 724{ 725 if (new_state & _NEW_MODELVIEW) { 726 _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); 727 728 /* Bring cull position uptodate. 729 */ 730 TRANSFORM_POINT3( ctx->Transform.CullObjPos, 731 ctx->ModelviewMatrixStack.Top->inv, 732 ctx->Transform.CullEyePos ); 733 } 734 735 736 if (new_state & _NEW_PROJECTION) 737 update_projection( ctx ); 738 739 /* Keep ModelviewProject uptodate always to allow tnl 740 * implementations that go model->clip even when eye is required. 741 */ 742 calculate_model_project_matrix(ctx); 743} 744 745/*@}*/ 746 747 748/**********************************************************************/ 749/** Matrix stack initialization */ 750/*@{*/ 751 752 753/** 754 * Initialize a matrix stack. 755 * 756 * \param stack matrix stack. 757 * \param maxDepth maximum stack depth. 758 * \param dirtyFlag dirty flag. 759 * 760 * Allocates an array of \p maxDepth elements for the matrix stack and calls 761 * _math_matrix_ctr() and _math_matrix_alloc_inv() for each element to 762 * initialize it. 763 */ 764static void 765init_matrix_stack( struct matrix_stack *stack, 766 GLuint maxDepth, GLuint dirtyFlag ) 767{ 768 GLuint i; 769 770 stack->Depth = 0; 771 stack->MaxDepth = maxDepth; 772 stack->DirtyFlag = dirtyFlag; 773 /* The stack */ 774 stack->Stack = (GLmatrix *) CALLOC(maxDepth * sizeof(GLmatrix)); 775 for (i = 0; i < maxDepth; i++) { 776 _math_matrix_ctr(&stack->Stack[i]); 777 _math_matrix_alloc_inv(&stack->Stack[i]); 778 } 779 stack->Top = stack->Stack; 780} 781 782/** 783 * Free matrix stack. 784 * 785 * \param stack matrix stack. 786 * 787 * Calls _math_matrix_dtr() for each element of the matrix stack and 788 * frees the array. 789 */ 790static void 791free_matrix_stack( struct matrix_stack *stack ) 792{ 793 GLuint i; 794 for (i = 0; i < stack->MaxDepth; i++) { 795 _math_matrix_dtr(&stack->Stack[i]); 796 } 797 FREE(stack->Stack); 798 stack->Stack = stack->Top = NULL; 799} 800 801/*@}*/ 802 803 804/**********************************************************************/ 805/** \name Initialization */ 806/*@{*/ 807 808 809/** 810 * Initialize the context matrix data. 811 * 812 * \param ctx GL context. 813 * 814 * Initializes each of the matrix stacks and the combined modelview-projection 815 * matrix. 816 */ 817void _mesa_init_matrix( GLcontext * ctx ) 818{ 819 GLint i; 820 821 /* Initialize matrix stacks */ 822 init_matrix_stack(&ctx->ModelviewMatrixStack, MAX_MODELVIEW_STACK_DEPTH, 823 _NEW_MODELVIEW); 824 init_matrix_stack(&ctx->ProjectionMatrixStack, MAX_PROJECTION_STACK_DEPTH, 825 _NEW_PROJECTION); 826 init_matrix_stack(&ctx->ColorMatrixStack, MAX_COLOR_STACK_DEPTH, 827 _NEW_COLOR_MATRIX); 828 for (i = 0; i < MAX_TEXTURE_UNITS; i++) 829 init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH, 830 _NEW_TEXTURE_MATRIX); 831 for (i = 0; i < MAX_PROGRAM_MATRICES; i++) 832 init_matrix_stack(&ctx->ProgramMatrixStack[i], 833 MAX_PROGRAM_MATRIX_STACK_DEPTH, _NEW_TRACK_MATRIX); 834 ctx->CurrentStack = &ctx->ModelviewMatrixStack; 835 836 /* Init combined Modelview*Projection matrix */ 837 _math_matrix_ctr( &ctx->_ModelProjectMatrix ); 838} 839 840 841/** 842 * Free the context matrix data. 843 * 844 * \param ctx GL context. 845 * 846 * Frees each of the matrix stacks and the combined modelview-projection 847 * matrix. 848 */ 849void _mesa_free_matrix_data( GLcontext *ctx ) 850{ 851 GLint i; 852 853 free_matrix_stack(&ctx->ModelviewMatrixStack); 854 free_matrix_stack(&ctx->ProjectionMatrixStack); 855 free_matrix_stack(&ctx->ColorMatrixStack); 856 for (i = 0; i < MAX_TEXTURE_UNITS; i++) 857 free_matrix_stack(&ctx->TextureMatrixStack[i]); 858 for (i = 0; i < MAX_PROGRAM_MATRICES; i++) 859 free_matrix_stack(&ctx->ProgramMatrixStack[i]); 860 /* combined Modelview*Projection matrix */ 861 _math_matrix_dtr( &ctx->_ModelProjectMatrix ); 862 863} 864 865 866/** 867 * Initialize the context transform attribute group. 868 * 869 * \param ctx GL context. 870 * 871 * \todo Move this to a new file with other 'transform' routines. 872 */ 873void _mesa_init_transform( GLcontext *ctx ) 874{ 875 GLint i; 876 877 /* Transformation group */ 878 ctx->Transform.MatrixMode = GL_MODELVIEW; 879 ctx->Transform.Normalize = GL_FALSE; 880 ctx->Transform.RescaleNormals = GL_FALSE; 881 ctx->Transform.RasterPositionUnclipped = GL_FALSE; 882 for (i=0;i<MAX_CLIP_PLANES;i++) { 883 ASSIGN_4V( ctx->Transform.EyeUserPlane[i], 0.0, 0.0, 0.0, 0.0 ); 884 } 885 ctx->Transform.ClipPlanesEnabled = 0; 886 887 ASSIGN_4V( ctx->Transform.CullObjPos, 0.0, 0.0, 1.0, 0.0 ); 888 ASSIGN_4V( ctx->Transform.CullEyePos, 0.0, 0.0, 1.0, 0.0 ); 889} 890 891 892/** 893 * Initialize the context viewport attribute group. 894 * 895 * \param ctx GL context. 896 * 897 * \todo Move this to a new file with other 'viewport' routines. 898 */ 899void _mesa_init_viewport( GLcontext *ctx ) 900{ 901 GLfloat depthMax = 65535.0F; /* sorf of arbitrary */ 902 903 /* Viewport group */ 904 ctx->Viewport.X = 0; 905 ctx->Viewport.Y = 0; 906 ctx->Viewport.Width = 0; 907 ctx->Viewport.Height = 0; 908 ctx->Viewport.Near = 0.0; 909 ctx->Viewport.Far = 1.0; 910 _math_matrix_ctr(&ctx->Viewport._WindowMap); 911 912 _math_matrix_viewport(&ctx->Viewport._WindowMap, 0, 0, 0, 0, 913 0.0F, 1.0F, depthMax); 914} 915 916 917/** 918 * Free the context viewport attribute group data. 919 * 920 * \param ctx GL context. 921 * 922 * \todo Move this to a new file with other 'viewport' routines. 923 */ 924void _mesa_free_viewport_data( GLcontext *ctx ) 925{ 926 _math_matrix_dtr(&ctx->Viewport._WindowMap); 927} 928 929/*@}*/ 930