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