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 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#include "api_exec_decl.h" 48 49 50static struct gl_matrix_stack * 51get_named_matrix_stack(struct gl_context *ctx, GLenum mode, const char* caller) 52{ 53 switch (mode) { 54 case GL_MODELVIEW: 55 return &ctx->ModelviewMatrixStack; 56 case GL_PROJECTION: 57 return &ctx->ProjectionMatrixStack; 58 case GL_TEXTURE: 59 /* This error check is disabled because if we're called from 60 * glPopAttrib() when the active texture unit is >= MaxTextureCoordUnits 61 * we'll generate an unexpected error. 62 * From the GL_ARB_vertex_shader spec it sounds like we should instead 63 * do error checking in other places when we actually try to access 64 * texture matrices beyond MaxTextureCoordUnits. 65 */ 66#if 0 67 if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { 68 _mesa_error(ctx, GL_INVALID_OPERATION, 69 "glMatrixMode(invalid tex unit %d)", 70 ctx->Texture.CurrentUnit); 71 return; 72 } 73#endif 74 assert(ctx->Texture.CurrentUnit < ARRAY_SIZE(ctx->TextureMatrixStack)); 75 return &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit]; 76 case GL_MATRIX0_ARB: 77 case GL_MATRIX1_ARB: 78 case GL_MATRIX2_ARB: 79 case GL_MATRIX3_ARB: 80 case GL_MATRIX4_ARB: 81 case GL_MATRIX5_ARB: 82 case GL_MATRIX6_ARB: 83 case GL_MATRIX7_ARB: 84 if (ctx->API == API_OPENGL_COMPAT 85 && (ctx->Extensions.ARB_vertex_program || 86 ctx->Extensions.ARB_fragment_program)) { 87 const GLuint m = mode - GL_MATRIX0_ARB; 88 if (m <= ctx->Const.MaxProgramMatrices) 89 return &ctx->ProgramMatrixStack[m]; 90 } 91 FALLTHROUGH; 92 default: 93 break; 94 } 95 if (mode >= GL_TEXTURE0 && mode < (GL_TEXTURE0 + ctx->Const.MaxTextureCoordUnits)) { 96 return &ctx->TextureMatrixStack[mode - GL_TEXTURE0]; 97 } 98 _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 99 return NULL; 100} 101 102 103static void matrix_frustum(struct gl_matrix_stack* stack, 104 GLdouble left, GLdouble right, 105 GLdouble bottom, GLdouble top, 106 GLdouble nearval, GLdouble farval, 107 const char* caller) 108{ 109 GET_CURRENT_CONTEXT(ctx); 110 if (nearval <= 0.0 || 111 farval <= 0.0 || 112 nearval == farval || 113 left == right || 114 top == bottom) { 115 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 116 return; 117 } 118 119 FLUSH_VERTICES(ctx, 0, 0); 120 121 _math_matrix_frustum(stack->Top, 122 (GLfloat) left, (GLfloat) right, 123 (GLfloat) bottom, (GLfloat) top, 124 (GLfloat) nearval, (GLfloat) farval); 125 ctx->NewState |= stack->DirtyFlag; 126} 127 128 129/** 130 * Apply a perspective projection matrix. 131 * 132 * \param left left clipping plane coordinate. 133 * \param right right clipping plane coordinate. 134 * \param bottom bottom clipping plane coordinate. 135 * \param top top clipping plane coordinate. 136 * \param nearval distance to the near clipping plane. 137 * \param farval distance to the far clipping plane. 138 * 139 * \sa glFrustum(). 140 * 141 * Flushes vertices and validates parameters. Calls _math_matrix_frustum() with 142 * the top matrix of the current matrix stack and sets 143 * __struct gl_contextRec::NewState. 144 */ 145void GLAPIENTRY 146_mesa_Frustum( GLdouble left, GLdouble right, 147 GLdouble bottom, GLdouble top, 148 GLdouble nearval, GLdouble farval ) 149{ 150 GET_CURRENT_CONTEXT(ctx); 151 matrix_frustum(ctx->CurrentStack, 152 (GLfloat) left, (GLfloat) right, 153 (GLfloat) bottom, (GLfloat) top, 154 (GLfloat) nearval, (GLfloat) farval, 155 "glFrustum"); 156} 157 158 159void GLAPIENTRY 160_mesa_MatrixFrustumEXT( GLenum matrixMode, 161 GLdouble left, GLdouble right, 162 GLdouble bottom, GLdouble top, 163 GLdouble nearval, GLdouble farval ) 164{ 165 GET_CURRENT_CONTEXT(ctx); 166 struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 167 "glMatrixFrustumEXT"); 168 if (!stack) 169 return; 170 171 matrix_frustum(stack, 172 (GLfloat) left, (GLfloat) right, 173 (GLfloat) bottom, (GLfloat) top, 174 (GLfloat) nearval, (GLfloat) farval, 175 "glMatrixFrustumEXT"); 176} 177 178 179static void 180matrix_ortho(struct gl_matrix_stack* stack, 181 GLdouble left, GLdouble right, 182 GLdouble bottom, GLdouble top, 183 GLdouble nearval, GLdouble farval, 184 const char* caller) 185{ 186 GET_CURRENT_CONTEXT(ctx); 187 188 if (MESA_VERBOSE & VERBOSE_API) 189 _mesa_debug(ctx, "%s(%f, %f, %f, %f, %f, %f)\n", caller, 190 left, right, bottom, top, nearval, farval); 191 192 if (left == right || 193 bottom == top || 194 nearval == farval) 195 { 196 _mesa_error( ctx, GL_INVALID_VALUE, "%s", caller ); 197 return; 198 } 199 200 FLUSH_VERTICES(ctx, 0, 0); 201 202 _math_matrix_ortho( stack->Top, 203 (GLfloat) left, (GLfloat) right, 204 (GLfloat) bottom, (GLfloat) top, 205 (GLfloat) nearval, (GLfloat) farval ); 206 ctx->NewState |= stack->DirtyFlag; 207} 208 209 210/** 211 * Apply an orthographic projection matrix. 212 * 213 * \param left left clipping plane coordinate. 214 * \param right right clipping plane coordinate. 215 * \param bottom bottom clipping plane coordinate. 216 * \param top top clipping plane coordinate. 217 * \param nearval distance to the near clipping plane. 218 * \param farval distance to the far clipping plane. 219 * 220 * \sa glOrtho(). 221 * 222 * Flushes vertices and validates parameters. Calls _math_matrix_ortho() with 223 * the top matrix of the current matrix stack and sets 224 * __struct gl_contextRec::NewState. 225 */ 226void GLAPIENTRY 227_mesa_Ortho( GLdouble left, GLdouble right, 228 GLdouble bottom, GLdouble top, 229 GLdouble nearval, GLdouble farval ) 230{ 231 GET_CURRENT_CONTEXT(ctx); 232 matrix_ortho(ctx->CurrentStack, 233 (GLfloat) left, (GLfloat) right, 234 (GLfloat) bottom, (GLfloat) top, 235 (GLfloat) nearval, (GLfloat) farval, 236 "glOrtho"); 237} 238 239 240void GLAPIENTRY 241_mesa_MatrixOrthoEXT( GLenum matrixMode, 242 GLdouble left, GLdouble right, 243 GLdouble bottom, GLdouble top, 244 GLdouble nearval, GLdouble farval ) 245{ 246 GET_CURRENT_CONTEXT(ctx); 247 struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 248 "glMatrixOrthoEXT"); 249 if (!stack) 250 return; 251 252 matrix_ortho(stack, 253 (GLfloat) left, (GLfloat) right, 254 (GLfloat) bottom, (GLfloat) top, 255 (GLfloat) nearval, (GLfloat) farval, 256 "glMatrixOrthoEXT"); 257} 258 259 260/** 261 * Set the current matrix stack. 262 * 263 * \param mode matrix stack. 264 * 265 * \sa glMatrixMode(). 266 * 267 * Flushes the vertices, validates the parameter and updates 268 * __struct gl_contextRec::CurrentStack and gl_transform_attrib::MatrixMode 269 * with the specified matrix stack. 270 */ 271void GLAPIENTRY 272_mesa_MatrixMode( GLenum mode ) 273{ 274 struct gl_matrix_stack * stack; 275 GET_CURRENT_CONTEXT(ctx); 276 277 if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE) 278 return; 279 280 if (mode >= GL_TEXTURE0 && mode < (GL_TEXTURE0 + ctx->Const.MaxTextureCoordUnits)) { 281 stack = NULL; 282 } else { 283 stack = get_named_matrix_stack(ctx, mode, "glMatrixMode"); 284 } 285 286 if (stack) { 287 ctx->CurrentStack = stack; 288 ctx->Transform.MatrixMode = mode; 289 ctx->PopAttribState |= GL_TRANSFORM_BIT; 290 } 291} 292 293 294static void 295push_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack, 296 GLenum matrixMode, const char *func) 297{ 298 if (stack->Depth + 1 >= stack->MaxDepth) { 299 if (ctx->Transform.MatrixMode == GL_TEXTURE) { 300 _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=GL_TEXTURE, unit=%d)", 301 func, ctx->Texture.CurrentUnit); 302 } else { 303 _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=%s)", 304 func, _mesa_enum_to_string(matrixMode)); 305 } 306 return; 307 } 308 309 if (stack->Depth + 1 >= stack->StackSize) { 310 unsigned new_stack_size = stack->StackSize * 2; 311 unsigned i; 312 GLmatrix *new_stack = realloc(stack->Stack, 313 sizeof(*new_stack) * new_stack_size); 314 315 if (!new_stack) { 316 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 317 return; 318 } 319 320 for (i = stack->StackSize; i < new_stack_size; i++) 321 _math_matrix_ctr(&new_stack[i]); 322 323 stack->Stack = new_stack; 324 stack->StackSize = new_stack_size; 325 } 326 327 _math_matrix_push_copy(&stack->Stack[stack->Depth + 1], 328 &stack->Stack[stack->Depth]); 329 stack->Depth++; 330 stack->Top = &(stack->Stack[stack->Depth]); 331} 332 333 334/** 335 * Push the current matrix stack. 336 * 337 * \sa glPushMatrix(). 338 * 339 * Verifies the current matrix stack is not full, and duplicates the top-most 340 * matrix in the stack. 341 * Marks __struct gl_contextRec::NewState with the stack dirty flag. 342 */ 343void GLAPIENTRY 344_mesa_PushMatrix( void ) 345{ 346 GET_CURRENT_CONTEXT(ctx); 347 struct gl_matrix_stack *stack = ctx->CurrentStack; 348 349 if (MESA_VERBOSE&VERBOSE_API) 350 _mesa_debug(ctx, "glPushMatrix %s\n", 351 _mesa_enum_to_string(ctx->Transform.MatrixMode)); 352 353 push_matrix(ctx, stack, ctx->Transform.MatrixMode, "glPushMatrix"); 354} 355 356 357void GLAPIENTRY 358_mesa_MatrixPushEXT( GLenum matrixMode ) 359{ 360 GET_CURRENT_CONTEXT(ctx); 361 struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 362 "glMatrixPushEXT"); 363 ASSERT_OUTSIDE_BEGIN_END(ctx); 364 if (stack) 365 push_matrix(ctx, stack, matrixMode, "glMatrixPushEXT"); 366} 367 368 369static GLboolean 370pop_matrix( struct gl_context *ctx, struct gl_matrix_stack *stack ) 371{ 372 if (stack->Depth == 0) 373 return GL_FALSE; 374 375 stack->Depth--; 376 377 /* If the popped matrix is the same as the current one, treat it as 378 * a no-op change. 379 */ 380 if (memcmp(stack->Top, &stack->Stack[stack->Depth], 381 sizeof(GLmatrix))) { 382 FLUSH_VERTICES(ctx, 0, 0); 383 ctx->NewState |= stack->DirtyFlag; 384 } 385 386 stack->Top = &(stack->Stack[stack->Depth]); 387 return GL_TRUE; 388} 389 390 391/** 392 * Pop the current matrix stack. 393 * 394 * \sa glPopMatrix(). 395 * 396 * Flushes the vertices, verifies the current matrix stack is not empty, and 397 * moves the stack head down. 398 * Marks __struct gl_contextRec::NewState with the dirty stack flag. 399 */ 400void GLAPIENTRY 401_mesa_PopMatrix( void ) 402{ 403 GET_CURRENT_CONTEXT(ctx); 404 struct gl_matrix_stack *stack = ctx->CurrentStack; 405 406 if (MESA_VERBOSE&VERBOSE_API) 407 _mesa_debug(ctx, "glPopMatrix %s\n", 408 _mesa_enum_to_string(ctx->Transform.MatrixMode)); 409 410 if (!pop_matrix(ctx, stack)) { 411 if (ctx->Transform.MatrixMode == GL_TEXTURE) { 412 _mesa_error(ctx, GL_STACK_UNDERFLOW, 413 "glPopMatrix(mode=GL_TEXTURE, unit=%d)", 414 ctx->Texture.CurrentUnit); 415 } 416 else { 417 _mesa_error(ctx, GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)", 418 _mesa_enum_to_string(ctx->Transform.MatrixMode)); 419 } 420 } 421} 422 423 424void GLAPIENTRY 425_mesa_MatrixPopEXT( GLenum matrixMode ) 426{ 427 GET_CURRENT_CONTEXT(ctx); 428 struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode, 429 "glMatrixPopEXT"); 430 if (!stack) 431 return; 432 433 if (!pop_matrix(ctx, stack)) { 434 if (matrixMode == GL_TEXTURE) { 435 _mesa_error(ctx, GL_STACK_UNDERFLOW, 436 "glMatrixPopEXT(mode=GL_TEXTURE, unit=%d)", 437 ctx->Texture.CurrentUnit); 438 } 439 else { 440 _mesa_error(ctx, GL_STACK_UNDERFLOW, "glMatrixPopEXT(mode=%s)", 441 _mesa_enum_to_string(matrixMode)); 442 } 443 } 444} 445 446 447void 448_mesa_load_identity_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack) 449{ 450 FLUSH_VERTICES(ctx, 0, 0); 451 452 _math_matrix_set_identity(stack->Top); 453 ctx->NewState |= stack->DirtyFlag; 454} 455 456 457/** 458 * Replace the current matrix with the identity matrix. 459 * 460 * \sa glLoadIdentity(). 461 * 462 * Flushes the vertices and calls _math_matrix_set_identity() with the 463 * top-most matrix in the current stack. 464 * Marks __struct gl_contextRec::NewState with the stack dirty flag. 465 */ 466void GLAPIENTRY 467_mesa_LoadIdentity( void ) 468{ 469 GET_CURRENT_CONTEXT(ctx); 470 471 if (MESA_VERBOSE & VERBOSE_API) 472 _mesa_debug(ctx, "glLoadIdentity()\n"); 473 474 _mesa_load_identity_matrix(ctx, ctx->CurrentStack); 475} 476 477 478void GLAPIENTRY 479_mesa_MatrixLoadIdentityEXT( GLenum matrixMode ) 480{ 481 struct gl_matrix_stack *stack; 482 GET_CURRENT_CONTEXT(ctx); 483 stack = get_named_matrix_stack(ctx, matrixMode, "glMatrixLoadIdentityEXT"); 484 if (!stack) 485 return; 486 487 _mesa_load_identity_matrix(ctx, stack); 488} 489 490 491void 492_mesa_load_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack, 493 const GLfloat *m) 494{ 495 if (memcmp(m, stack->Top->m, 16 * sizeof(GLfloat)) != 0) { 496 FLUSH_VERTICES(ctx, 0, 0); 497 _math_matrix_loadf(stack->Top, m); 498 ctx->NewState |= stack->DirtyFlag; 499 } 500} 501 502 503static void 504matrix_load(struct gl_context *ctx, struct gl_matrix_stack *stack, 505 const GLfloat *m, const char* caller) 506{ 507 if (!m) return; 508 if (MESA_VERBOSE & VERBOSE_API) 509 _mesa_debug(ctx, 510 "%s(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 511 caller, 512 m[0], m[4], m[8], m[12], 513 m[1], m[5], m[9], m[13], 514 m[2], m[6], m[10], m[14], 515 m[3], m[7], m[11], m[15]); 516 517 _mesa_load_matrix(ctx, stack, m); 518} 519 520 521/** 522 * Replace the current matrix with a given matrix. 523 * 524 * \param m matrix. 525 * 526 * \sa glLoadMatrixf(). 527 * 528 * Flushes the vertices and calls _math_matrix_loadf() with the top-most 529 * matrix in the current stack and the given matrix. 530 * Marks __struct gl_contextRec::NewState with the dirty stack flag. 531 */ 532void GLAPIENTRY 533_mesa_LoadMatrixf( const GLfloat *m ) 534{ 535 GET_CURRENT_CONTEXT(ctx); 536 matrix_load(ctx, ctx->CurrentStack, m, "glLoadMatrix"); 537} 538 539 540/** 541 * Replace the named matrix with a given matrix. 542 * 543 * \param matrixMode matrix to replace 544 * \param m matrix 545 * 546 * \sa glLoadMatrixf(). 547 */ 548void GLAPIENTRY 549_mesa_MatrixLoadfEXT( GLenum matrixMode, const GLfloat *m ) 550{ 551 GET_CURRENT_CONTEXT(ctx); 552 struct gl_matrix_stack * stack = 553 get_named_matrix_stack(ctx, matrixMode, "glMatrixLoadfEXT"); 554 if (!stack) 555 return; 556 557 matrix_load(ctx, stack, m, "glMatrixLoadfEXT"); 558} 559 560 561static void 562matrix_mult(struct gl_matrix_stack *stack, const GLfloat *m, const char* caller) 563{ 564 GET_CURRENT_CONTEXT(ctx); 565 if (!m || 566 (m[0] == 1 && m[1] == 0 && m[2] == 0 && m[3] == 0 && 567 m[4] == 0 && m[5] == 1 && m[6] == 0 && m[7] == 0 && 568 m[8] == 0 && m[9] == 0 && m[10] == 1 && m[11] == 0 && 569 m[12] == 0 && m[13] == 0 && m[14] == 0 && m[15] == 1)) 570 return; 571 if (MESA_VERBOSE & VERBOSE_API) 572 _mesa_debug(ctx, 573 "%s(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n", 574 caller, 575 m[0], m[4], m[8], m[12], 576 m[1], m[5], m[9], m[13], 577 m[2], m[6], m[10], m[14], 578 m[3], m[7], m[11], m[15]); 579 580 FLUSH_VERTICES(ctx, 0, 0); 581 _math_matrix_mul_floats(stack->Top, m); 582 ctx->NewState |= stack->DirtyFlag; 583} 584 585 586/** 587 * Multiply the current matrix with a given matrix. 588 * 589 * \param m matrix. 590 * 591 * \sa glMultMatrixf(). 592 * 593 * Flushes the vertices and calls _math_matrix_mul_floats() with the top-most 594 * matrix in the current stack and the given matrix. Marks 595 * __struct gl_contextRec::NewState with the dirty stack flag. 596 */ 597void GLAPIENTRY 598_mesa_MultMatrixf( const GLfloat *m ) 599{ 600 GET_CURRENT_CONTEXT(ctx); 601 matrix_mult(ctx->CurrentStack, m, "glMultMatrix"); 602} 603 604 605void GLAPIENTRY 606_mesa_MatrixMultfEXT( GLenum matrixMode, const GLfloat *m ) 607{ 608 GET_CURRENT_CONTEXT(ctx); 609 struct gl_matrix_stack * stack = 610 get_named_matrix_stack(ctx, matrixMode, "glMatrixMultfEXT"); 611 if (!stack) 612 return; 613 614 matrix_mult(stack, m, "glMultMatrix"); 615} 616 617 618static void 619matrix_rotate(struct gl_matrix_stack *stack, GLfloat angle, 620 GLfloat x, GLfloat y, GLfloat z, const char* caller) 621{ 622 GET_CURRENT_CONTEXT(ctx); 623 624 FLUSH_VERTICES(ctx, 0, 0); 625 if (angle != 0.0F) { 626 _math_matrix_rotate(stack->Top, angle, x, y, z); 627 ctx->NewState |=stack->DirtyFlag; 628 } 629} 630 631 632/** 633 * Multiply the current matrix with a rotation matrix. 634 * 635 * \param angle angle of rotation, in degrees. 636 * \param x rotation vector x coordinate. 637 * \param y rotation vector y coordinate. 638 * \param z rotation vector z coordinate. 639 * 640 * \sa glRotatef(). 641 * 642 * Flushes the vertices and calls _math_matrix_rotate() with the top-most 643 * matrix in the current stack and the given parameters. Marks 644 * __struct gl_contextRec::NewState with the dirty stack flag. 645 */ 646void GLAPIENTRY 647_mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) 648{ 649 GET_CURRENT_CONTEXT(ctx); 650 matrix_rotate(ctx->CurrentStack, angle, x, y, z, "glRotatef"); 651} 652 653 654void GLAPIENTRY 655_mesa_MatrixRotatefEXT( GLenum matrixMode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) 656{ 657 GET_CURRENT_CONTEXT(ctx); 658 struct gl_matrix_stack *stack = 659 get_named_matrix_stack(ctx, matrixMode, "glMatrixRotatefEXT"); 660 if (!stack) 661 return; 662 663 matrix_rotate(stack, angle, x, y, z, "glMatrixRotatefEXT"); 664} 665 666 667/** 668 * Multiply the current matrix with a general scaling matrix. 669 * 670 * \param x x axis scale factor. 671 * \param y y axis scale factor. 672 * \param z z axis scale factor. 673 * 674 * \sa glScalef(). 675 * 676 * Flushes the vertices and calls _math_matrix_scale() with the top-most 677 * matrix in the current stack and the given parameters. Marks 678 * __struct gl_contextRec::NewState with the dirty stack flag. 679 */ 680void GLAPIENTRY 681_mesa_Scalef( GLfloat x, GLfloat y, GLfloat z ) 682{ 683 GET_CURRENT_CONTEXT(ctx); 684 685 FLUSH_VERTICES(ctx, 0, 0); 686 _math_matrix_scale( ctx->CurrentStack->Top, x, y, z); 687 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 688} 689 690 691void GLAPIENTRY 692_mesa_MatrixScalefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ) 693{ 694 struct gl_matrix_stack *stack; 695 GET_CURRENT_CONTEXT(ctx); 696 697 stack = get_named_matrix_stack(ctx, matrixMode, "glMatrixScalefEXT"); 698 if (!stack) 699 return; 700 701 FLUSH_VERTICES(ctx, 0, 0); 702 _math_matrix_scale(stack->Top, x, y, z); 703 ctx->NewState |= stack->DirtyFlag; 704} 705 706 707/** 708 * Multiply the current matrix with a translation matrix. 709 * 710 * \param x translation vector x coordinate. 711 * \param y translation vector y coordinate. 712 * \param z translation vector z coordinate. 713 * 714 * \sa glTranslatef(). 715 * 716 * Flushes the vertices and calls _math_matrix_translate() with the top-most 717 * matrix in the current stack and the given parameters. Marks 718 * __struct gl_contextRec::NewState with the dirty stack flag. 719 */ 720void GLAPIENTRY 721_mesa_Translatef( GLfloat x, GLfloat y, GLfloat z ) 722{ 723 GET_CURRENT_CONTEXT(ctx); 724 725 FLUSH_VERTICES(ctx, 0, 0); 726 _math_matrix_translate( ctx->CurrentStack->Top, x, y, z); 727 ctx->NewState |= ctx->CurrentStack->DirtyFlag; 728} 729 730 731void GLAPIENTRY 732_mesa_MatrixTranslatefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ) 733{ 734 GET_CURRENT_CONTEXT(ctx); 735 struct gl_matrix_stack *stack = 736 get_named_matrix_stack(ctx, matrixMode, "glMatrixTranslatefEXT"); 737 if (!stack) 738 return; 739 740 FLUSH_VERTICES(ctx, 0, 0); 741 _math_matrix_translate(stack->Top, x, y, z); 742 ctx->NewState |= stack->DirtyFlag; 743} 744 745 746void GLAPIENTRY 747_mesa_LoadMatrixd( const GLdouble *m ) 748{ 749 GLint i; 750 GLfloat f[16]; 751 if (!m) return; 752 for (i = 0; i < 16; i++) 753 f[i] = (GLfloat) m[i]; 754 _mesa_LoadMatrixf(f); 755} 756 757 758void GLAPIENTRY 759_mesa_MatrixLoaddEXT( GLenum matrixMode, const GLdouble *m ) 760{ 761 GLfloat f[16]; 762 if (!m) return; 763 for (unsigned i = 0; i < 16; i++) 764 f[i] = (GLfloat) m[i]; 765 _mesa_MatrixLoadfEXT(matrixMode, f); 766} 767 768 769void GLAPIENTRY 770_mesa_MultMatrixd( const GLdouble *m ) 771{ 772 GLint i; 773 GLfloat f[16]; 774 if (!m) return; 775 for (i = 0; i < 16; i++) 776 f[i] = (GLfloat) m[i]; 777 _mesa_MultMatrixf( f ); 778} 779 780 781void GLAPIENTRY 782_mesa_MatrixMultdEXT( GLenum matrixMode, const GLdouble *m ) 783{ 784 GLfloat f[16]; 785 if (!m) return; 786 for (unsigned i = 0; i < 16; i++) 787 f[i] = (GLfloat) m[i]; 788 _mesa_MatrixMultfEXT(matrixMode, f); 789} 790 791 792void GLAPIENTRY 793_mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) 794{ 795 _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z); 796} 797 798 799void GLAPIENTRY 800_mesa_MatrixRotatedEXT( GLenum matrixMode, GLdouble angle, 801 GLdouble x, GLdouble y, GLdouble z ) 802{ 803 _mesa_MatrixRotatefEXT(matrixMode, (GLfloat) angle, 804 (GLfloat) x, (GLfloat) y, (GLfloat) z); 805} 806 807 808void GLAPIENTRY 809_mesa_Scaled( GLdouble x, GLdouble y, GLdouble z ) 810{ 811 _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z); 812} 813 814 815void GLAPIENTRY 816_mesa_MatrixScaledEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z ) 817{ 818 _mesa_MatrixScalefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) z); 819} 820 821 822void GLAPIENTRY 823_mesa_Translated( GLdouble x, GLdouble y, GLdouble z ) 824{ 825 _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z); 826} 827 828 829void GLAPIENTRY 830_mesa_MatrixTranslatedEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z ) 831{ 832 _mesa_MatrixTranslatefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) z); 833} 834 835 836void GLAPIENTRY 837_mesa_LoadTransposeMatrixf( const GLfloat *m ) 838{ 839 GLfloat tm[16]; 840 if (!m) return; 841 _math_transposef(tm, m); 842 _mesa_LoadMatrixf(tm); 843} 844 845void GLAPIENTRY 846_mesa_MatrixLoadTransposefEXT( GLenum matrixMode, const GLfloat *m ) 847{ 848 GLfloat tm[16]; 849 if (!m) return; 850 _math_transposef(tm, m); 851 _mesa_MatrixLoadfEXT(matrixMode, tm); 852} 853 854void GLAPIENTRY 855_mesa_LoadTransposeMatrixd( const GLdouble *m ) 856{ 857 GLfloat tm[16]; 858 if (!m) return; 859 _math_transposefd(tm, m); 860 _mesa_LoadMatrixf(tm); 861} 862 863void GLAPIENTRY 864_mesa_MatrixLoadTransposedEXT( GLenum matrixMode, const GLdouble *m ) 865{ 866 GLfloat tm[16]; 867 if (!m) return; 868 _math_transposefd(tm, m); 869 _mesa_MatrixLoadfEXT(matrixMode, tm); 870} 871 872void GLAPIENTRY 873_mesa_MultTransposeMatrixf( const GLfloat *m ) 874{ 875 GLfloat tm[16]; 876 if (!m) return; 877 _math_transposef(tm, m); 878 _mesa_MultMatrixf(tm); 879} 880 881void GLAPIENTRY 882_mesa_MatrixMultTransposefEXT( GLenum matrixMode, const GLfloat *m ) 883{ 884 GLfloat tm[16]; 885 if (!m) return; 886 _math_transposef(tm, m); 887 _mesa_MatrixMultfEXT(matrixMode, tm); 888} 889 890void GLAPIENTRY 891_mesa_MultTransposeMatrixd( const GLdouble *m ) 892{ 893 GLfloat tm[16]; 894 if (!m) return; 895 _math_transposefd(tm, m); 896 _mesa_MultMatrixf(tm); 897} 898 899void GLAPIENTRY 900_mesa_MatrixMultTransposedEXT( GLenum matrixMode, const GLdouble *m ) 901{ 902 GLfloat tm[16]; 903 if (!m) return; 904 _math_transposefd(tm, m); 905 _mesa_MatrixMultfEXT(matrixMode, tm); 906} 907 908/**********************************************************************/ 909/** \name State management */ 910/*@{*/ 911 912 913/** 914 * Update the projection matrix stack. 915 * 916 * \param ctx GL context. 917 * 918 * Recomputes user clip positions if necessary. 919 * 920 * \note This routine references __struct gl_contextRec::Tranform attribute 921 * values to compute userclip positions in clip space, but is only called on 922 * _NEW_PROJECTION. The _mesa_ClipPlane() function keeps these values up to 923 * date across changes to the __struct gl_contextRec::Transform attributes. 924 */ 925static void 926update_projection( struct gl_context *ctx ) 927{ 928 /* Recompute clip plane positions in clipspace. This is also done 929 * in _mesa_ClipPlane(). 930 */ 931 GLbitfield mask = ctx->Transform.ClipPlanesEnabled; 932 933 if (mask) { 934 /* make sure the inverse is up to date */ 935 _math_matrix_analyse(ctx->ProjectionMatrixStack.Top); 936 937 do { 938 const int p = u_bit_scan(&mask); 939 940 _mesa_transform_vector(ctx->Transform._ClipUserPlane[p], 941 ctx->Transform.EyeUserPlane[p], 942 ctx->ProjectionMatrixStack.Top->inv); 943 } while (mask); 944 } 945} 946 947 948/** 949 * Updates the combined modelview-projection matrix. 950 * 951 * \param ctx GL context. 952 * \param new_state new state bit mask. 953 * 954 * If there is a new model view matrix then analyzes it. If there is a new 955 * projection matrix, updates it. Finally calls 956 * calculate_model_project_matrix() to recalculate the modelview-projection 957 * matrix. 958 */ 959void _mesa_update_modelview_project( struct gl_context *ctx, GLuint new_state ) 960{ 961 if (new_state & _NEW_MODELVIEW) 962 _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); 963 964 if (new_state & _NEW_PROJECTION) 965 update_projection( ctx ); 966 967 /* Calculate ModelViewMatrix * ProjectionMatrix. */ 968 _math_matrix_mul_matrix(&ctx->_ModelProjectMatrix, 969 ctx->ProjectionMatrixStack.Top, 970 ctx->ModelviewMatrixStack.Top); 971} 972 973/*@}*/ 974 975 976/**********************************************************************/ 977/** Matrix stack initialization */ 978/*@{*/ 979 980 981/** 982 * Initialize a matrix stack. 983 * 984 * \param stack matrix stack. 985 * \param maxDepth maximum stack depth. 986 * \param dirtyFlag dirty flag. 987 * 988 * Allocates an array of \p maxDepth elements for the matrix stack and calls 989 * _math_matrix_ctr() for each element to initialize it. 990 */ 991static void 992init_matrix_stack(struct gl_matrix_stack *stack, 993 GLuint maxDepth, GLuint dirtyFlag) 994{ 995 stack->Depth = 0; 996 stack->MaxDepth = maxDepth; 997 stack->DirtyFlag = dirtyFlag; 998 /* The stack will be dynamically resized at glPushMatrix() time */ 999 stack->Stack = calloc(1, sizeof(GLmatrix)); 1000 stack->StackSize = 1; 1001 _math_matrix_ctr(&stack->Stack[0]); 1002 stack->Top = stack->Stack; 1003} 1004 1005/** 1006 * Free matrix stack. 1007 * 1008 * \param stack matrix stack. 1009 */ 1010static void 1011free_matrix_stack( struct gl_matrix_stack *stack ) 1012{ 1013 free(stack->Stack); 1014 stack->Stack = stack->Top = NULL; 1015 stack->StackSize = 0; 1016} 1017 1018/*@}*/ 1019 1020 1021/**********************************************************************/ 1022/** \name Initialization */ 1023/*@{*/ 1024 1025 1026/** 1027 * Initialize the context matrix data. 1028 * 1029 * \param ctx GL context. 1030 * 1031 * Initializes each of the matrix stacks and the combined modelview-projection 1032 * matrix. 1033 */ 1034void _mesa_init_matrix( struct gl_context * ctx ) 1035{ 1036 GLuint i; 1037 1038 /* Initialize matrix stacks */ 1039 init_matrix_stack(&ctx->ModelviewMatrixStack, MAX_MODELVIEW_STACK_DEPTH, 1040 _NEW_MODELVIEW); 1041 init_matrix_stack(&ctx->ProjectionMatrixStack, MAX_PROJECTION_STACK_DEPTH, 1042 _NEW_PROJECTION); 1043 for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++) 1044 init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH, 1045 _NEW_TEXTURE_MATRIX); 1046 for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++) 1047 init_matrix_stack(&ctx->ProgramMatrixStack[i], 1048 MAX_PROGRAM_MATRIX_STACK_DEPTH, _NEW_TRACK_MATRIX); 1049 ctx->CurrentStack = &ctx->ModelviewMatrixStack; 1050 1051 /* Init combined Modelview*Projection matrix */ 1052 _math_matrix_ctr( &ctx->_ModelProjectMatrix ); 1053} 1054 1055 1056/** 1057 * Free the context matrix data. 1058 * 1059 * \param ctx GL context. 1060 * 1061 * Frees each of the matrix stacks. 1062 */ 1063void _mesa_free_matrix_data( struct gl_context *ctx ) 1064{ 1065 GLuint i; 1066 1067 free_matrix_stack(&ctx->ModelviewMatrixStack); 1068 free_matrix_stack(&ctx->ProjectionMatrixStack); 1069 for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++) 1070 free_matrix_stack(&ctx->TextureMatrixStack[i]); 1071 for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++) 1072 free_matrix_stack(&ctx->ProgramMatrixStack[i]); 1073 1074} 1075 1076 1077/** 1078 * Initialize the context transform attribute group. 1079 * 1080 * \param ctx GL context. 1081 * 1082 * \todo Move this to a new file with other 'transform' routines. 1083 */ 1084void _mesa_init_transform( struct gl_context *ctx ) 1085{ 1086 GLuint i; 1087 1088 /* Transformation group */ 1089 ctx->Transform.MatrixMode = GL_MODELVIEW; 1090 ctx->Transform.Normalize = GL_FALSE; 1091 ctx->Transform.RescaleNormals = GL_FALSE; 1092 ctx->Transform.RasterPositionUnclipped = GL_FALSE; 1093 for (i=0;i<ctx->Const.MaxClipPlanes;i++) { 1094 ASSIGN_4V( ctx->Transform.EyeUserPlane[i], 0.0, 0.0, 0.0, 0.0 ); 1095 } 1096 ctx->Transform.ClipPlanesEnabled = 0; 1097} 1098 1099 1100/*@}*/ 1101