1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * \file matrix.c
29848b8605Smrg * Matrix operations.
30848b8605Smrg *
31848b8605Smrg * \note
32848b8605Smrg * -# 4x4 transformation matrices are stored in memory in column major order.
33848b8605Smrg * -# Points/vertices are to be thought of as column vectors.
34848b8605Smrg * -# Transformation of a point p by a matrix M is: p' = M * p
35848b8605Smrg */
36848b8605Smrg
37848b8605Smrg
38848b8605Smrg#include "glheader.h"
39848b8605Smrg#include "imports.h"
40848b8605Smrg#include "context.h"
41848b8605Smrg#include "enums.h"
42848b8605Smrg#include "macros.h"
43848b8605Smrg#include "matrix.h"
44848b8605Smrg#include "mtypes.h"
45848b8605Smrg#include "math/m_matrix.h"
46b8e80941Smrg#include "util/bitscan.h"
47848b8605Smrg
48848b8605Smrg
49848b8605Smrg/**
50848b8605Smrg * Apply a perspective projection matrix.
51848b8605Smrg *
52848b8605Smrg * \param left left clipping plane coordinate.
53848b8605Smrg * \param right right clipping plane coordinate.
54848b8605Smrg * \param bottom bottom clipping plane coordinate.
55848b8605Smrg * \param top top clipping plane coordinate.
56848b8605Smrg * \param nearval distance to the near clipping plane.
57848b8605Smrg * \param farval distance to the far clipping plane.
58848b8605Smrg *
59848b8605Smrg * \sa glFrustum().
60848b8605Smrg *
61848b8605Smrg * Flushes vertices and validates parameters. Calls _math_matrix_frustum() with
62848b8605Smrg * the top matrix of the current matrix stack and sets
63848b8605Smrg * __struct gl_contextRec::NewState.
64848b8605Smrg */
65848b8605Smrgvoid GLAPIENTRY
66848b8605Smrg_mesa_Frustum( GLdouble left, GLdouble right,
67848b8605Smrg               GLdouble bottom, GLdouble top,
68848b8605Smrg               GLdouble nearval, GLdouble farval )
69848b8605Smrg{
70848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
71848b8605Smrg
72848b8605Smrg   FLUSH_VERTICES(ctx, 0);
73848b8605Smrg
74848b8605Smrg   if (nearval <= 0.0 ||
75848b8605Smrg       farval <= 0.0 ||
76848b8605Smrg       nearval == farval ||
77848b8605Smrg       left == right ||
78848b8605Smrg       top == bottom)
79848b8605Smrg   {
80848b8605Smrg      _mesa_error( ctx,  GL_INVALID_VALUE, "glFrustum" );
81848b8605Smrg      return;
82848b8605Smrg   }
83848b8605Smrg
84848b8605Smrg   _math_matrix_frustum( ctx->CurrentStack->Top,
85848b8605Smrg                         (GLfloat) left, (GLfloat) right,
86848b8605Smrg			 (GLfloat) bottom, (GLfloat) top,
87848b8605Smrg			 (GLfloat) nearval, (GLfloat) farval );
88848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
89848b8605Smrg}
90848b8605Smrg
91848b8605Smrg
92848b8605Smrg/**
93848b8605Smrg * Apply an orthographic projection matrix.
94848b8605Smrg *
95848b8605Smrg * \param left left clipping plane coordinate.
96848b8605Smrg * \param right right clipping plane coordinate.
97848b8605Smrg * \param bottom bottom clipping plane coordinate.
98848b8605Smrg * \param top top clipping plane coordinate.
99848b8605Smrg * \param nearval distance to the near clipping plane.
100848b8605Smrg * \param farval distance to the far clipping plane.
101848b8605Smrg *
102848b8605Smrg * \sa glOrtho().
103848b8605Smrg *
104848b8605Smrg * Flushes vertices and validates parameters. Calls _math_matrix_ortho() with
105848b8605Smrg * the top matrix of the current matrix stack and sets
106848b8605Smrg * __struct gl_contextRec::NewState.
107848b8605Smrg */
108848b8605Smrgvoid GLAPIENTRY
109848b8605Smrg_mesa_Ortho( GLdouble left, GLdouble right,
110848b8605Smrg             GLdouble bottom, GLdouble top,
111848b8605Smrg             GLdouble nearval, GLdouble farval )
112848b8605Smrg{
113848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
114848b8605Smrg
115848b8605Smrg   FLUSH_VERTICES(ctx, 0);
116848b8605Smrg
117848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
118848b8605Smrg      _mesa_debug(ctx, "glOrtho(%f, %f, %f, %f, %f, %f)\n",
119848b8605Smrg                  left, right, bottom, top, nearval, farval);
120848b8605Smrg
121848b8605Smrg   if (left == right ||
122848b8605Smrg       bottom == top ||
123848b8605Smrg       nearval == farval)
124848b8605Smrg   {
125848b8605Smrg      _mesa_error( ctx,  GL_INVALID_VALUE, "glOrtho" );
126848b8605Smrg      return;
127848b8605Smrg   }
128848b8605Smrg
129848b8605Smrg   _math_matrix_ortho( ctx->CurrentStack->Top,
130848b8605Smrg                       (GLfloat) left, (GLfloat) right,
131848b8605Smrg		       (GLfloat) bottom, (GLfloat) top,
132848b8605Smrg		       (GLfloat) nearval, (GLfloat) farval );
133848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
134848b8605Smrg}
135848b8605Smrg
136848b8605Smrg
137848b8605Smrg/**
138848b8605Smrg * Set the current matrix stack.
139848b8605Smrg *
140848b8605Smrg * \param mode matrix stack.
141848b8605Smrg *
142848b8605Smrg * \sa glMatrixMode().
143848b8605Smrg *
144848b8605Smrg * Flushes the vertices, validates the parameter and updates
145848b8605Smrg * __struct gl_contextRec::CurrentStack and gl_transform_attrib::MatrixMode
146848b8605Smrg * with the specified matrix stack.
147848b8605Smrg */
148848b8605Smrgvoid GLAPIENTRY
149848b8605Smrg_mesa_MatrixMode( GLenum mode )
150848b8605Smrg{
151848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
152848b8605Smrg
153848b8605Smrg   if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE)
154848b8605Smrg      return;
155848b8605Smrg
156848b8605Smrg   switch (mode) {
157848b8605Smrg   case GL_MODELVIEW:
158848b8605Smrg      ctx->CurrentStack = &ctx->ModelviewMatrixStack;
159848b8605Smrg      break;
160848b8605Smrg   case GL_PROJECTION:
161848b8605Smrg      ctx->CurrentStack = &ctx->ProjectionMatrixStack;
162848b8605Smrg      break;
163848b8605Smrg   case GL_TEXTURE:
164848b8605Smrg      /* This error check is disabled because if we're called from
165848b8605Smrg       * glPopAttrib() when the active texture unit is >= MaxTextureCoordUnits
166848b8605Smrg       * we'll generate an unexpected error.
167848b8605Smrg       * From the GL_ARB_vertex_shader spec it sounds like we should instead
168848b8605Smrg       * do error checking in other places when we actually try to access
169848b8605Smrg       * texture matrices beyond MaxTextureCoordUnits.
170848b8605Smrg       */
171848b8605Smrg#if 0
172848b8605Smrg      if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
173848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
174848b8605Smrg                     "glMatrixMode(invalid tex unit %d)",
175848b8605Smrg                     ctx->Texture.CurrentUnit);
176848b8605Smrg         return;
177848b8605Smrg      }
178848b8605Smrg#endif
179b8e80941Smrg      assert(ctx->Texture.CurrentUnit < ARRAY_SIZE(ctx->TextureMatrixStack));
180848b8605Smrg      ctx->CurrentStack = &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit];
181848b8605Smrg      break;
182848b8605Smrg   case GL_MATRIX0_ARB:
183848b8605Smrg   case GL_MATRIX1_ARB:
184848b8605Smrg   case GL_MATRIX2_ARB:
185848b8605Smrg   case GL_MATRIX3_ARB:
186848b8605Smrg   case GL_MATRIX4_ARB:
187848b8605Smrg   case GL_MATRIX5_ARB:
188848b8605Smrg   case GL_MATRIX6_ARB:
189848b8605Smrg   case GL_MATRIX7_ARB:
190848b8605Smrg      if (ctx->API == API_OPENGL_COMPAT
191848b8605Smrg          && (ctx->Extensions.ARB_vertex_program ||
192848b8605Smrg              ctx->Extensions.ARB_fragment_program)) {
193848b8605Smrg         const GLuint m = mode - GL_MATRIX0_ARB;
194848b8605Smrg         if (m > ctx->Const.MaxProgramMatrices) {
195848b8605Smrg            _mesa_error(ctx, GL_INVALID_ENUM,
196848b8605Smrg                        "glMatrixMode(GL_MATRIX%d_ARB)", m);
197848b8605Smrg            return;
198848b8605Smrg         }
199848b8605Smrg         ctx->CurrentStack = &ctx->ProgramMatrixStack[m];
200848b8605Smrg      }
201848b8605Smrg      else {
202848b8605Smrg         _mesa_error( ctx,  GL_INVALID_ENUM, "glMatrixMode(mode)" );
203848b8605Smrg         return;
204848b8605Smrg      }
205848b8605Smrg      break;
206848b8605Smrg   default:
207848b8605Smrg      _mesa_error( ctx,  GL_INVALID_ENUM, "glMatrixMode(mode)" );
208848b8605Smrg      return;
209848b8605Smrg   }
210848b8605Smrg
211848b8605Smrg   ctx->Transform.MatrixMode = mode;
212848b8605Smrg}
213848b8605Smrg
214848b8605Smrg
215848b8605Smrg/**
216848b8605Smrg * Push the current matrix stack.
217848b8605Smrg *
218848b8605Smrg * \sa glPushMatrix().
219848b8605Smrg *
220848b8605Smrg * Verifies the current matrix stack is not full, and duplicates the top-most
221848b8605Smrg * matrix in the stack.
222848b8605Smrg * Marks __struct gl_contextRec::NewState with the stack dirty flag.
223848b8605Smrg */
224848b8605Smrgvoid GLAPIENTRY
225848b8605Smrg_mesa_PushMatrix( void )
226848b8605Smrg{
227848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
228848b8605Smrg   struct gl_matrix_stack *stack = ctx->CurrentStack;
229848b8605Smrg
230848b8605Smrg   if (MESA_VERBOSE&VERBOSE_API)
231848b8605Smrg      _mesa_debug(ctx, "glPushMatrix %s\n",
232b8e80941Smrg                  _mesa_enum_to_string(ctx->Transform.MatrixMode));
233848b8605Smrg
234848b8605Smrg   if (stack->Depth + 1 >= stack->MaxDepth) {
235848b8605Smrg      if (ctx->Transform.MatrixMode == GL_TEXTURE) {
236848b8605Smrg         _mesa_error(ctx,  GL_STACK_OVERFLOW,
237848b8605Smrg                     "glPushMatrix(mode=GL_TEXTURE, unit=%d)",
238848b8605Smrg                      ctx->Texture.CurrentUnit);
239848b8605Smrg      }
240848b8605Smrg      else {
241848b8605Smrg         _mesa_error(ctx,  GL_STACK_OVERFLOW, "glPushMatrix(mode=%s)",
242b8e80941Smrg                     _mesa_enum_to_string(ctx->Transform.MatrixMode));
243848b8605Smrg      }
244848b8605Smrg      return;
245848b8605Smrg   }
246b8e80941Smrg   if (stack->Depth + 1 >= stack->StackSize) {
247b8e80941Smrg      unsigned new_stack_size = stack->StackSize * 2;
248b8e80941Smrg      unsigned i;
249b8e80941Smrg      GLmatrix *new_stack = realloc(stack->Stack,
250b8e80941Smrg                                    sizeof(*new_stack) * new_stack_size);
251b8e80941Smrg
252b8e80941Smrg      if (!new_stack) {
253b8e80941Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushMatrix()");
254b8e80941Smrg         return;
255b8e80941Smrg      }
256b8e80941Smrg
257b8e80941Smrg      for (i = stack->StackSize; i < new_stack_size; i++)
258b8e80941Smrg         _math_matrix_ctr(&new_stack[i]);
259b8e80941Smrg
260b8e80941Smrg      stack->Stack = new_stack;
261b8e80941Smrg      stack->StackSize = new_stack_size;
262b8e80941Smrg   }
263b8e80941Smrg
264848b8605Smrg   _math_matrix_copy( &stack->Stack[stack->Depth + 1],
265848b8605Smrg                      &stack->Stack[stack->Depth] );
266848b8605Smrg   stack->Depth++;
267848b8605Smrg   stack->Top = &(stack->Stack[stack->Depth]);
268848b8605Smrg   ctx->NewState |= stack->DirtyFlag;
269848b8605Smrg}
270848b8605Smrg
271848b8605Smrg
272848b8605Smrg/**
273848b8605Smrg * Pop the current matrix stack.
274848b8605Smrg *
275848b8605Smrg * \sa glPopMatrix().
276848b8605Smrg *
277848b8605Smrg * Flushes the vertices, verifies the current matrix stack is not empty, and
278848b8605Smrg * moves the stack head down.
279848b8605Smrg * Marks __struct gl_contextRec::NewState with the dirty stack flag.
280848b8605Smrg */
281848b8605Smrgvoid GLAPIENTRY
282848b8605Smrg_mesa_PopMatrix( void )
283848b8605Smrg{
284848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
285848b8605Smrg   struct gl_matrix_stack *stack = ctx->CurrentStack;
286848b8605Smrg
287848b8605Smrg   FLUSH_VERTICES(ctx, 0);
288848b8605Smrg
289848b8605Smrg   if (MESA_VERBOSE&VERBOSE_API)
290848b8605Smrg      _mesa_debug(ctx, "glPopMatrix %s\n",
291b8e80941Smrg                  _mesa_enum_to_string(ctx->Transform.MatrixMode));
292848b8605Smrg
293848b8605Smrg   if (stack->Depth == 0) {
294848b8605Smrg      if (ctx->Transform.MatrixMode == GL_TEXTURE) {
295848b8605Smrg         _mesa_error(ctx,  GL_STACK_UNDERFLOW,
296848b8605Smrg                     "glPopMatrix(mode=GL_TEXTURE, unit=%d)",
297848b8605Smrg                      ctx->Texture.CurrentUnit);
298848b8605Smrg      }
299848b8605Smrg      else {
300848b8605Smrg         _mesa_error(ctx,  GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)",
301b8e80941Smrg                     _mesa_enum_to_string(ctx->Transform.MatrixMode));
302848b8605Smrg      }
303848b8605Smrg      return;
304848b8605Smrg   }
305848b8605Smrg   stack->Depth--;
306848b8605Smrg   stack->Top = &(stack->Stack[stack->Depth]);
307848b8605Smrg   ctx->NewState |= stack->DirtyFlag;
308848b8605Smrg}
309848b8605Smrg
310848b8605Smrg
311848b8605Smrg/**
312848b8605Smrg * Replace the current matrix with the identity matrix.
313848b8605Smrg *
314848b8605Smrg * \sa glLoadIdentity().
315848b8605Smrg *
316848b8605Smrg * Flushes the vertices and calls _math_matrix_set_identity() with the
317848b8605Smrg * top-most matrix in the current stack.
318848b8605Smrg * Marks __struct gl_contextRec::NewState with the stack dirty flag.
319848b8605Smrg */
320848b8605Smrgvoid GLAPIENTRY
321848b8605Smrg_mesa_LoadIdentity( void )
322848b8605Smrg{
323848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
324848b8605Smrg
325848b8605Smrg   FLUSH_VERTICES(ctx, 0);
326848b8605Smrg
327848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
328848b8605Smrg      _mesa_debug(ctx, "glLoadIdentity()\n");
329848b8605Smrg
330848b8605Smrg   _math_matrix_set_identity( ctx->CurrentStack->Top );
331848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
332848b8605Smrg}
333848b8605Smrg
334848b8605Smrg
335848b8605Smrg/**
336848b8605Smrg * Replace the current matrix with a given matrix.
337848b8605Smrg *
338848b8605Smrg * \param m matrix.
339848b8605Smrg *
340848b8605Smrg * \sa glLoadMatrixf().
341848b8605Smrg *
342848b8605Smrg * Flushes the vertices and calls _math_matrix_loadf() with the top-most
343848b8605Smrg * matrix in the current stack and the given matrix.
344848b8605Smrg * Marks __struct gl_contextRec::NewState with the dirty stack flag.
345848b8605Smrg */
346848b8605Smrgvoid GLAPIENTRY
347848b8605Smrg_mesa_LoadMatrixf( const GLfloat *m )
348848b8605Smrg{
349848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
350848b8605Smrg   if (!m) return;
351848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
352848b8605Smrg      _mesa_debug(ctx,
353848b8605Smrg          "glLoadMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
354848b8605Smrg          m[0], m[4], m[8], m[12],
355848b8605Smrg          m[1], m[5], m[9], m[13],
356848b8605Smrg          m[2], m[6], m[10], m[14],
357848b8605Smrg          m[3], m[7], m[11], m[15]);
358848b8605Smrg
359b8e80941Smrg   if (memcmp(m, ctx->CurrentStack->Top->m, 16 * sizeof(GLfloat)) != 0) {
360b8e80941Smrg      FLUSH_VERTICES(ctx, 0);
361b8e80941Smrg      _math_matrix_loadf( ctx->CurrentStack->Top, m );
362b8e80941Smrg      ctx->NewState |= ctx->CurrentStack->DirtyFlag;
363b8e80941Smrg   }
364848b8605Smrg}
365848b8605Smrg
366848b8605Smrg
367848b8605Smrg/**
368848b8605Smrg * Multiply the current matrix with a given matrix.
369848b8605Smrg *
370848b8605Smrg * \param m matrix.
371848b8605Smrg *
372848b8605Smrg * \sa glMultMatrixf().
373848b8605Smrg *
374848b8605Smrg * Flushes the vertices and calls _math_matrix_mul_floats() with the top-most
375848b8605Smrg * matrix in the current stack and the given matrix. Marks
376848b8605Smrg * __struct gl_contextRec::NewState with the dirty stack flag.
377848b8605Smrg */
378848b8605Smrgvoid GLAPIENTRY
379848b8605Smrg_mesa_MultMatrixf( const GLfloat *m )
380848b8605Smrg{
381848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
382848b8605Smrg   if (!m) return;
383848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
384848b8605Smrg      _mesa_debug(ctx,
385848b8605Smrg          "glMultMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
386848b8605Smrg          m[0], m[4], m[8], m[12],
387848b8605Smrg          m[1], m[5], m[9], m[13],
388848b8605Smrg          m[2], m[6], m[10], m[14],
389848b8605Smrg          m[3], m[7], m[11], m[15]);
390848b8605Smrg
391848b8605Smrg   FLUSH_VERTICES(ctx, 0);
392848b8605Smrg   _math_matrix_mul_floats( ctx->CurrentStack->Top, m );
393848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
394848b8605Smrg}
395848b8605Smrg
396848b8605Smrg
397848b8605Smrg/**
398848b8605Smrg * Multiply the current matrix with a rotation matrix.
399848b8605Smrg *
400848b8605Smrg * \param angle angle of rotation, in degrees.
401848b8605Smrg * \param x rotation vector x coordinate.
402848b8605Smrg * \param y rotation vector y coordinate.
403848b8605Smrg * \param z rotation vector z coordinate.
404848b8605Smrg *
405848b8605Smrg * \sa glRotatef().
406848b8605Smrg *
407848b8605Smrg * Flushes the vertices and calls _math_matrix_rotate() with the top-most
408848b8605Smrg * matrix in the current stack and the given parameters. Marks
409848b8605Smrg * __struct gl_contextRec::NewState with the dirty stack flag.
410848b8605Smrg */
411848b8605Smrgvoid GLAPIENTRY
412848b8605Smrg_mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
413848b8605Smrg{
414848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
415848b8605Smrg
416848b8605Smrg   FLUSH_VERTICES(ctx, 0);
417848b8605Smrg   if (angle != 0.0F) {
418848b8605Smrg      _math_matrix_rotate( ctx->CurrentStack->Top, angle, x, y, z);
419848b8605Smrg      ctx->NewState |= ctx->CurrentStack->DirtyFlag;
420848b8605Smrg   }
421848b8605Smrg}
422848b8605Smrg
423848b8605Smrg
424848b8605Smrg/**
425848b8605Smrg * Multiply the current matrix with a general scaling matrix.
426848b8605Smrg *
427848b8605Smrg * \param x x axis scale factor.
428848b8605Smrg * \param y y axis scale factor.
429848b8605Smrg * \param z z axis scale factor.
430848b8605Smrg *
431848b8605Smrg * \sa glScalef().
432848b8605Smrg *
433848b8605Smrg * Flushes the vertices and calls _math_matrix_scale() with the top-most
434848b8605Smrg * matrix in the current stack and the given parameters. Marks
435848b8605Smrg * __struct gl_contextRec::NewState with the dirty stack flag.
436848b8605Smrg */
437848b8605Smrgvoid GLAPIENTRY
438848b8605Smrg_mesa_Scalef( GLfloat x, GLfloat y, GLfloat z )
439848b8605Smrg{
440848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
441848b8605Smrg
442848b8605Smrg   FLUSH_VERTICES(ctx, 0);
443848b8605Smrg   _math_matrix_scale( ctx->CurrentStack->Top, x, y, z);
444848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
445848b8605Smrg}
446848b8605Smrg
447848b8605Smrg
448848b8605Smrg/**
449848b8605Smrg * Multiply the current matrix with a translation matrix.
450848b8605Smrg *
451848b8605Smrg * \param x translation vector x coordinate.
452848b8605Smrg * \param y translation vector y coordinate.
453848b8605Smrg * \param z translation vector z coordinate.
454848b8605Smrg *
455848b8605Smrg * \sa glTranslatef().
456848b8605Smrg *
457848b8605Smrg * Flushes the vertices and calls _math_matrix_translate() with the top-most
458848b8605Smrg * matrix in the current stack and the given parameters. Marks
459848b8605Smrg * __struct gl_contextRec::NewState with the dirty stack flag.
460848b8605Smrg */
461848b8605Smrgvoid GLAPIENTRY
462848b8605Smrg_mesa_Translatef( GLfloat x, GLfloat y, GLfloat z )
463848b8605Smrg{
464848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
465848b8605Smrg
466848b8605Smrg   FLUSH_VERTICES(ctx, 0);
467848b8605Smrg   _math_matrix_translate( ctx->CurrentStack->Top, x, y, z);
468848b8605Smrg   ctx->NewState |= ctx->CurrentStack->DirtyFlag;
469848b8605Smrg}
470848b8605Smrg
471848b8605Smrg
472848b8605Smrgvoid GLAPIENTRY
473848b8605Smrg_mesa_LoadMatrixd( const GLdouble *m )
474848b8605Smrg{
475848b8605Smrg   GLint i;
476848b8605Smrg   GLfloat f[16];
477848b8605Smrg   if (!m) return;
478848b8605Smrg   for (i = 0; i < 16; i++)
479848b8605Smrg      f[i] = (GLfloat) m[i];
480848b8605Smrg   _mesa_LoadMatrixf(f);
481848b8605Smrg}
482848b8605Smrg
483848b8605Smrgvoid GLAPIENTRY
484848b8605Smrg_mesa_MultMatrixd( const GLdouble *m )
485848b8605Smrg{
486848b8605Smrg   GLint i;
487848b8605Smrg   GLfloat f[16];
488848b8605Smrg   if (!m) return;
489848b8605Smrg   for (i = 0; i < 16; i++)
490848b8605Smrg      f[i] = (GLfloat) m[i];
491848b8605Smrg   _mesa_MultMatrixf( f );
492848b8605Smrg}
493848b8605Smrg
494848b8605Smrg
495848b8605Smrgvoid GLAPIENTRY
496848b8605Smrg_mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z )
497848b8605Smrg{
498848b8605Smrg   _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z);
499848b8605Smrg}
500848b8605Smrg
501848b8605Smrg
502848b8605Smrgvoid GLAPIENTRY
503848b8605Smrg_mesa_Scaled( GLdouble x, GLdouble y, GLdouble z )
504848b8605Smrg{
505848b8605Smrg   _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z);
506848b8605Smrg}
507848b8605Smrg
508848b8605Smrg
509848b8605Smrgvoid GLAPIENTRY
510848b8605Smrg_mesa_Translated( GLdouble x, GLdouble y, GLdouble z )
511848b8605Smrg{
512848b8605Smrg   _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z);
513848b8605Smrg}
514848b8605Smrg
515848b8605Smrg
516848b8605Smrgvoid GLAPIENTRY
517848b8605Smrg_mesa_LoadTransposeMatrixf( const GLfloat *m )
518848b8605Smrg{
519848b8605Smrg   GLfloat tm[16];
520848b8605Smrg   if (!m) return;
521848b8605Smrg   _math_transposef(tm, m);
522848b8605Smrg   _mesa_LoadMatrixf(tm);
523848b8605Smrg}
524848b8605Smrg
525848b8605Smrg
526848b8605Smrgvoid GLAPIENTRY
527848b8605Smrg_mesa_LoadTransposeMatrixd( const GLdouble *m )
528848b8605Smrg{
529848b8605Smrg   GLfloat tm[16];
530848b8605Smrg   if (!m) return;
531848b8605Smrg   _math_transposefd(tm, m);
532848b8605Smrg   _mesa_LoadMatrixf(tm);
533848b8605Smrg}
534848b8605Smrg
535848b8605Smrg
536848b8605Smrgvoid GLAPIENTRY
537848b8605Smrg_mesa_MultTransposeMatrixf( const GLfloat *m )
538848b8605Smrg{
539848b8605Smrg   GLfloat tm[16];
540848b8605Smrg   if (!m) return;
541848b8605Smrg   _math_transposef(tm, m);
542848b8605Smrg   _mesa_MultMatrixf(tm);
543848b8605Smrg}
544848b8605Smrg
545848b8605Smrg
546848b8605Smrgvoid GLAPIENTRY
547848b8605Smrg_mesa_MultTransposeMatrixd( const GLdouble *m )
548848b8605Smrg{
549848b8605Smrg   GLfloat tm[16];
550848b8605Smrg   if (!m) return;
551848b8605Smrg   _math_transposefd(tm, m);
552848b8605Smrg   _mesa_MultMatrixf(tm);
553848b8605Smrg}
554848b8605Smrg
555848b8605Smrg
556848b8605Smrg
557848b8605Smrg/**********************************************************************/
558848b8605Smrg/** \name State management */
559848b8605Smrg/*@{*/
560848b8605Smrg
561848b8605Smrg
562848b8605Smrg/**
563848b8605Smrg * Update the projection matrix stack.
564848b8605Smrg *
565848b8605Smrg * \param ctx GL context.
566848b8605Smrg *
567848b8605Smrg * Calls _math_matrix_analyse() with the top-matrix of the projection matrix
568848b8605Smrg * stack, and recomputes user clip positions if necessary.
569848b8605Smrg *
570848b8605Smrg * \note This routine references __struct gl_contextRec::Tranform attribute
571848b8605Smrg * values to compute userclip positions in clip space, but is only called on
572848b8605Smrg * _NEW_PROJECTION.  The _mesa_ClipPlane() function keeps these values up to
573848b8605Smrg * date across changes to the __struct gl_contextRec::Transform attributes.
574848b8605Smrg */
575848b8605Smrgstatic void
576848b8605Smrgupdate_projection( struct gl_context *ctx )
577848b8605Smrg{
578b8e80941Smrg   GLbitfield mask;
579b8e80941Smrg
580848b8605Smrg   _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );
581848b8605Smrg
582848b8605Smrg   /* Recompute clip plane positions in clipspace.  This is also done
583848b8605Smrg    * in _mesa_ClipPlane().
584848b8605Smrg    */
585b8e80941Smrg   mask = ctx->Transform.ClipPlanesEnabled;
586b8e80941Smrg   while (mask) {
587b8e80941Smrg      const int p = u_bit_scan(&mask);
588b8e80941Smrg
589b8e80941Smrg      _mesa_transform_vector( ctx->Transform._ClipUserPlane[p],
590b8e80941Smrg                              ctx->Transform.EyeUserPlane[p],
591b8e80941Smrg                              ctx->ProjectionMatrixStack.Top->inv );
592848b8605Smrg   }
593848b8605Smrg}
594848b8605Smrg
595848b8605Smrg
596848b8605Smrg/**
597848b8605Smrg * Calculate the combined modelview-projection matrix.
598848b8605Smrg *
599848b8605Smrg * \param ctx GL context.
600848b8605Smrg *
601848b8605Smrg * Multiplies the top matrices of the projection and model view stacks into
602848b8605Smrg * __struct gl_contextRec::_ModelProjectMatrix via _math_matrix_mul_matrix()
603848b8605Smrg * and analyzes the resulting matrix via _math_matrix_analyse().
604848b8605Smrg */
605848b8605Smrgstatic void
606848b8605Smrgcalculate_model_project_matrix( struct gl_context *ctx )
607848b8605Smrg{
608848b8605Smrg   _math_matrix_mul_matrix( &ctx->_ModelProjectMatrix,
609848b8605Smrg                            ctx->ProjectionMatrixStack.Top,
610848b8605Smrg                            ctx->ModelviewMatrixStack.Top );
611848b8605Smrg
612848b8605Smrg   _math_matrix_analyse( &ctx->_ModelProjectMatrix );
613848b8605Smrg}
614848b8605Smrg
615848b8605Smrg
616848b8605Smrg/**
617848b8605Smrg * Updates the combined modelview-projection matrix.
618848b8605Smrg *
619848b8605Smrg * \param ctx GL context.
620848b8605Smrg * \param new_state new state bit mask.
621848b8605Smrg *
622848b8605Smrg * If there is a new model view matrix then analyzes it. If there is a new
623848b8605Smrg * projection matrix, updates it. Finally calls
624848b8605Smrg * calculate_model_project_matrix() to recalculate the modelview-projection
625848b8605Smrg * matrix.
626848b8605Smrg */
627848b8605Smrgvoid _mesa_update_modelview_project( struct gl_context *ctx, GLuint new_state )
628848b8605Smrg{
629848b8605Smrg   if (new_state & _NEW_MODELVIEW)
630848b8605Smrg      _math_matrix_analyse( ctx->ModelviewMatrixStack.Top );
631848b8605Smrg
632848b8605Smrg   if (new_state & _NEW_PROJECTION)
633848b8605Smrg      update_projection( ctx );
634848b8605Smrg
635848b8605Smrg   /* Keep ModelviewProject up to date always to allow tnl
636848b8605Smrg    * implementations that go model->clip even when eye is required.
637848b8605Smrg    */
638848b8605Smrg   calculate_model_project_matrix(ctx);
639848b8605Smrg}
640848b8605Smrg
641848b8605Smrg/*@}*/
642848b8605Smrg
643848b8605Smrg
644848b8605Smrg/**********************************************************************/
645848b8605Smrg/** Matrix stack initialization */
646848b8605Smrg/*@{*/
647848b8605Smrg
648848b8605Smrg
649848b8605Smrg/**
650848b8605Smrg * Initialize a matrix stack.
651848b8605Smrg *
652848b8605Smrg * \param stack matrix stack.
653848b8605Smrg * \param maxDepth maximum stack depth.
654848b8605Smrg * \param dirtyFlag dirty flag.
655848b8605Smrg *
656848b8605Smrg * Allocates an array of \p maxDepth elements for the matrix stack and calls
657848b8605Smrg * _math_matrix_ctr() for each element to initialize it.
658848b8605Smrg */
659848b8605Smrgstatic void
660b8e80941Smrginit_matrix_stack(struct gl_matrix_stack *stack,
661b8e80941Smrg                  GLuint maxDepth, GLuint dirtyFlag)
662848b8605Smrg{
663848b8605Smrg   stack->Depth = 0;
664848b8605Smrg   stack->MaxDepth = maxDepth;
665848b8605Smrg   stack->DirtyFlag = dirtyFlag;
666b8e80941Smrg   /* The stack will be dynamically resized at glPushMatrix() time */
667b8e80941Smrg   stack->Stack = calloc(1, sizeof(GLmatrix));
668b8e80941Smrg   stack->StackSize = 1;
669b8e80941Smrg   _math_matrix_ctr(&stack->Stack[0]);
670848b8605Smrg   stack->Top = stack->Stack;
671848b8605Smrg}
672848b8605Smrg
673848b8605Smrg/**
674848b8605Smrg * Free matrix stack.
675848b8605Smrg *
676848b8605Smrg * \param stack matrix stack.
677848b8605Smrg *
678848b8605Smrg * Calls _math_matrix_dtr() for each element of the matrix stack and
679848b8605Smrg * frees the array.
680848b8605Smrg */
681848b8605Smrgstatic void
682848b8605Smrgfree_matrix_stack( struct gl_matrix_stack *stack )
683848b8605Smrg{
684848b8605Smrg   GLuint i;
685b8e80941Smrg   for (i = 0; i < stack->StackSize; i++) {
686848b8605Smrg      _math_matrix_dtr(&stack->Stack[i]);
687848b8605Smrg   }
688848b8605Smrg   free(stack->Stack);
689848b8605Smrg   stack->Stack = stack->Top = NULL;
690b8e80941Smrg   stack->StackSize = 0;
691848b8605Smrg}
692848b8605Smrg
693848b8605Smrg/*@}*/
694848b8605Smrg
695848b8605Smrg
696848b8605Smrg/**********************************************************************/
697848b8605Smrg/** \name Initialization */
698848b8605Smrg/*@{*/
699848b8605Smrg
700848b8605Smrg
701848b8605Smrg/**
702848b8605Smrg * Initialize the context matrix data.
703848b8605Smrg *
704848b8605Smrg * \param ctx GL context.
705848b8605Smrg *
706848b8605Smrg * Initializes each of the matrix stacks and the combined modelview-projection
707848b8605Smrg * matrix.
708848b8605Smrg */
709848b8605Smrgvoid _mesa_init_matrix( struct gl_context * ctx )
710848b8605Smrg{
711b8e80941Smrg   GLuint i;
712848b8605Smrg
713848b8605Smrg   /* Initialize matrix stacks */
714848b8605Smrg   init_matrix_stack(&ctx->ModelviewMatrixStack, MAX_MODELVIEW_STACK_DEPTH,
715848b8605Smrg                     _NEW_MODELVIEW);
716848b8605Smrg   init_matrix_stack(&ctx->ProjectionMatrixStack, MAX_PROJECTION_STACK_DEPTH,
717848b8605Smrg                     _NEW_PROJECTION);
718b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++)
719848b8605Smrg      init_matrix_stack(&ctx->TextureMatrixStack[i], MAX_TEXTURE_STACK_DEPTH,
720848b8605Smrg                        _NEW_TEXTURE_MATRIX);
721b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++)
722b8e80941Smrg      init_matrix_stack(&ctx->ProgramMatrixStack[i],
723848b8605Smrg		        MAX_PROGRAM_MATRIX_STACK_DEPTH, _NEW_TRACK_MATRIX);
724848b8605Smrg   ctx->CurrentStack = &ctx->ModelviewMatrixStack;
725848b8605Smrg
726848b8605Smrg   /* Init combined Modelview*Projection matrix */
727848b8605Smrg   _math_matrix_ctr( &ctx->_ModelProjectMatrix );
728848b8605Smrg}
729848b8605Smrg
730848b8605Smrg
731848b8605Smrg/**
732848b8605Smrg * Free the context matrix data.
733848b8605Smrg *
734848b8605Smrg * \param ctx GL context.
735848b8605Smrg *
736848b8605Smrg * Frees each of the matrix stacks and the combined modelview-projection
737848b8605Smrg * matrix.
738848b8605Smrg */
739848b8605Smrgvoid _mesa_free_matrix_data( struct gl_context *ctx )
740848b8605Smrg{
741b8e80941Smrg   GLuint i;
742848b8605Smrg
743848b8605Smrg   free_matrix_stack(&ctx->ModelviewMatrixStack);
744848b8605Smrg   free_matrix_stack(&ctx->ProjectionMatrixStack);
745b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(ctx->TextureMatrixStack); i++)
746848b8605Smrg      free_matrix_stack(&ctx->TextureMatrixStack[i]);
747b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(ctx->ProgramMatrixStack); i++)
748848b8605Smrg      free_matrix_stack(&ctx->ProgramMatrixStack[i]);
749848b8605Smrg   /* combined Modelview*Projection matrix */
750848b8605Smrg   _math_matrix_dtr( &ctx->_ModelProjectMatrix );
751848b8605Smrg
752848b8605Smrg}
753848b8605Smrg
754848b8605Smrg
755848b8605Smrg/**
756848b8605Smrg * Initialize the context transform attribute group.
757848b8605Smrg *
758848b8605Smrg * \param ctx GL context.
759848b8605Smrg *
760848b8605Smrg * \todo Move this to a new file with other 'transform' routines.
761848b8605Smrg */
762848b8605Smrgvoid _mesa_init_transform( struct gl_context *ctx )
763848b8605Smrg{
764848b8605Smrg   GLuint i;
765848b8605Smrg
766848b8605Smrg   /* Transformation group */
767848b8605Smrg   ctx->Transform.MatrixMode = GL_MODELVIEW;
768848b8605Smrg   ctx->Transform.Normalize = GL_FALSE;
769848b8605Smrg   ctx->Transform.RescaleNormals = GL_FALSE;
770848b8605Smrg   ctx->Transform.RasterPositionUnclipped = GL_FALSE;
771848b8605Smrg   for (i=0;i<ctx->Const.MaxClipPlanes;i++) {
772848b8605Smrg      ASSIGN_4V( ctx->Transform.EyeUserPlane[i], 0.0, 0.0, 0.0, 0.0 );
773848b8605Smrg   }
774848b8605Smrg   ctx->Transform.ClipPlanesEnabled = 0;
775848b8605Smrg}
776848b8605Smrg
777848b8605Smrg
778848b8605Smrg/*@}*/
779