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