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