added some _mesa_debug() calls
[mesa.git] / src / mesa / main / matrix.c
1 /* $Id: matrix.c,v 1.43 2002/06/23 02:52:18 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 /*
29 * Matrix operations
30 *
31 * NOTES:
32 * 1. 4x4 transformation matrices are stored in memory in column major order.
33 * 2. Points/vertices are to be thought of as column vectors.
34 * 3. Transformation of a point p by a matrix M is: p' = M * p
35 */
36
37
38 #ifdef PC_HEADER
39 #include "all.h"
40 #else
41 #include "glheader.h"
42 #include "buffers.h"
43 #include "context.h"
44 #include "enums.h"
45 #include "macros.h"
46 #include "matrix.h"
47 #include "mem.h"
48 #include "mmath.h"
49 #include "mtypes.h"
50
51 #include "math/m_matrix.h"
52 #endif
53
54
55 void
56 _mesa_Frustum( GLdouble left, GLdouble right,
57 GLdouble bottom, GLdouble top,
58 GLdouble nearval, GLdouble farval )
59 {
60 GET_CURRENT_CONTEXT(ctx);
61 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
62
63 if (nearval <= 0.0 ||
64 farval <= 0.0 ||
65 nearval == farval ||
66 left == right ||
67 top == bottom)
68 {
69 _mesa_error( ctx, GL_INVALID_VALUE, "glFrustum" );
70 return;
71 }
72
73 _math_matrix_frustum( ctx->CurrentStack->Top,
74 (GLfloat) left, (GLfloat) right,
75 (GLfloat) bottom, (GLfloat) top,
76 (GLfloat) nearval, (GLfloat) farval );
77 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
78 }
79
80
81 void
82 _mesa_Ortho( GLdouble left, GLdouble right,
83 GLdouble bottom, GLdouble top,
84 GLdouble nearval, GLdouble farval )
85 {
86 GET_CURRENT_CONTEXT(ctx);
87 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
88
89 if (MESA_VERBOSE & VERBOSE_API)
90 _mesa_debug(ctx, "glFrustum(%f, %f, %f, %f, %f, %f)\n",
91 left, right, bottom, top, nearval, farval);
92
93 if (left == right ||
94 bottom == top ||
95 nearval == farval)
96 {
97 _mesa_error( ctx, GL_INVALID_VALUE, "glOrtho" );
98 return;
99 }
100
101 _math_matrix_ortho( ctx->CurrentStack->Top,
102 (GLfloat) left, (GLfloat) right,
103 (GLfloat) bottom, (GLfloat) top,
104 (GLfloat) nearval, (GLfloat) farval );
105 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
106 }
107
108
109 void
110 _mesa_MatrixMode( GLenum mode )
111 {
112 GET_CURRENT_CONTEXT(ctx);
113 ASSERT_OUTSIDE_BEGIN_END(ctx);
114
115 if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE)
116 return;
117 FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
118
119 switch (mode) {
120 case GL_MODELVIEW:
121 ctx->CurrentStack = &ctx->ModelviewMatrixStack;
122 break;
123 case GL_PROJECTION:
124 ctx->CurrentStack = &ctx->ProjectionMatrixStack;
125 break;
126 case GL_TEXTURE:
127 ctx->CurrentStack = &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit];
128 break;
129 case GL_COLOR:
130 ctx->CurrentStack = &ctx->ColorMatrixStack;
131 break;
132 case GL_MATRIX0_NV:
133 case GL_MATRIX1_NV:
134 case GL_MATRIX2_NV:
135 case GL_MATRIX3_NV:
136 case GL_MATRIX4_NV:
137 case GL_MATRIX5_NV:
138 case GL_MATRIX6_NV:
139 case GL_MATRIX7_NV:
140 if (!ctx->Extensions.NV_vertex_program) {
141 _mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode" );
142 return;
143 }
144 ctx->CurrentStack = &ctx->ProgramMatrixStack[mode - GL_MATRIX0_NV];
145 break;
146 default:
147 _mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode" );
148 return;
149 }
150
151 ctx->Transform.MatrixMode = mode;
152 }
153
154
155
156 void
157 _mesa_PushMatrix( void )
158 {
159 GET_CURRENT_CONTEXT(ctx);
160 struct matrix_stack *stack = ctx->CurrentStack;
161 ASSERT_OUTSIDE_BEGIN_END(ctx);
162
163 if (MESA_VERBOSE&VERBOSE_API)
164 _mesa_debug(ctx, "glPushMatrix %s\n",
165 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode));
166
167 if (stack->Depth + 1 >= stack->MaxDepth) {
168 _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix" );
169 return;
170 }
171 _math_matrix_copy( &stack->Stack[stack->Depth + 1],
172 &stack->Stack[stack->Depth] );
173 stack->Depth++;
174 stack->Top = &(stack->Stack[stack->Depth]);
175 ctx->NewState |= stack->DirtyFlag;
176 }
177
178
179
180 void
181 _mesa_PopMatrix( void )
182 {
183 GET_CURRENT_CONTEXT(ctx);
184 struct matrix_stack *stack = ctx->CurrentStack;
185 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
186
187 if (MESA_VERBOSE&VERBOSE_API)
188 _mesa_debug(ctx, "glPopMatrix %s\n",
189 _mesa_lookup_enum_by_nr(ctx->Transform.MatrixMode));
190
191 if (stack->Depth == 0) {
192 _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix" );
193 return;
194 }
195 stack->Depth--;
196 stack->Top = &(stack->Stack[stack->Depth]);
197 ctx->NewState |= stack->DirtyFlag;
198 }
199
200
201
202 void
203 _mesa_LoadIdentity( void )
204 {
205 GET_CURRENT_CONTEXT(ctx);
206 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
207
208 if (MESA_VERBOSE & VERBOSE_API)
209 _mesa_debug(ctx, "glLoadIdentity()");
210
211 _math_matrix_set_identity( ctx->CurrentStack->Top );
212 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
213 }
214
215
216 void
217 _mesa_LoadMatrixf( const GLfloat *m )
218 {
219 GET_CURRENT_CONTEXT(ctx);
220 if (!m) return;
221 if (MESA_VERBOSE & VERBOSE_API)
222 _mesa_debug(ctx,
223 "glLoadMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
224 m[0], m[4], m[8], m[12],
225 m[1], m[5], m[9], m[13],
226 m[2], m[6], m[10], m[14],
227 m[3], m[7], m[11], m[15]);
228
229 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
230 _math_matrix_loadf( ctx->CurrentStack->Top, m );
231 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
232 }
233
234
235 void
236 _mesa_LoadMatrixd( const GLdouble *m )
237 {
238 GLint i;
239 GLfloat f[16];
240 if (!m) return;
241 for (i = 0; i < 16; i++)
242 f[i] = (GLfloat) m[i];
243 _mesa_LoadMatrixf(f);
244 }
245
246
247
248 /*
249 * Multiply the active matrix by an arbitary matrix.
250 */
251 void
252 _mesa_MultMatrixf( const GLfloat *m )
253 {
254 GET_CURRENT_CONTEXT(ctx);
255 if (!m) return;
256 if (MESA_VERBOSE & VERBOSE_API)
257 _mesa_debug(ctx,
258 "glMultMatrix(%f %f %f %f, %f %f %f %f, %f %f %f %f, %f %f %f %f\n",
259 m[0], m[4], m[8], m[12],
260 m[1], m[5], m[9], m[13],
261 m[2], m[6], m[10], m[14],
262 m[3], m[7], m[11], m[15]);
263 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
264 _math_matrix_mul_floats( ctx->CurrentStack->Top, m );
265 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
266 }
267
268
269 /*
270 * Multiply the active matrix by an arbitary matrix.
271 */
272 void
273 _mesa_MultMatrixd( const GLdouble *m )
274 {
275 GLint i;
276 GLfloat f[16];
277 if (!m) return;
278 for (i = 0; i < 16; i++)
279 f[i] = (GLfloat) m[i];
280 _mesa_MultMatrixf( f );
281 }
282
283
284
285
286 /*
287 * Execute a glRotate call
288 */
289 void
290 _mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
291 {
292 GET_CURRENT_CONTEXT(ctx);
293 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
294 if (angle != 0.0F) {
295 _math_matrix_rotate( ctx->CurrentStack->Top, angle, x, y, z);
296 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
297 }
298 }
299
300 void
301 _mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z )
302 {
303 _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z);
304 }
305
306
307 /*
308 * Execute a glScale call
309 */
310 void
311 _mesa_Scalef( GLfloat x, GLfloat y, GLfloat z )
312 {
313 GET_CURRENT_CONTEXT(ctx);
314 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
315 _math_matrix_scale( ctx->CurrentStack->Top, x, y, z);
316 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
317 }
318
319
320 void
321 _mesa_Scaled( GLdouble x, GLdouble y, GLdouble z )
322 {
323 _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z);
324 }
325
326
327 /*
328 * Execute a glTranslate call
329 */
330 void
331 _mesa_Translatef( GLfloat x, GLfloat y, GLfloat z )
332 {
333 GET_CURRENT_CONTEXT(ctx);
334 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
335 _math_matrix_translate( ctx->CurrentStack->Top, x, y, z);
336 ctx->NewState |= ctx->CurrentStack->DirtyFlag;
337 }
338
339
340 void
341 _mesa_Translated( GLdouble x, GLdouble y, GLdouble z )
342 {
343 _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z);
344 }
345
346
347 void
348 _mesa_LoadTransposeMatrixfARB( const GLfloat *m )
349 {
350 GLfloat tm[16];
351 if (!m) return;
352 _math_transposef(tm, m);
353 _mesa_LoadMatrixf(tm);
354 }
355
356
357 void
358 _mesa_LoadTransposeMatrixdARB( const GLdouble *m )
359 {
360 GLfloat tm[16];
361 if (!m) return;
362 _math_transposefd(tm, m);
363 _mesa_LoadMatrixf(tm);
364 }
365
366
367 void
368 _mesa_MultTransposeMatrixfARB( const GLfloat *m )
369 {
370 GLfloat tm[16];
371 if (!m) return;
372 _math_transposef(tm, m);
373 _mesa_MultMatrixf(tm);
374 }
375
376
377 void
378 _mesa_MultTransposeMatrixdARB( const GLdouble *m )
379 {
380 GLfloat tm[16];
381 if (!m) return;
382 _math_transposefd(tm, m);
383 _mesa_MultMatrixf(tm);
384 }
385
386
387 /*
388 * Called via glViewport or display list execution.
389 */
390 void
391 _mesa_Viewport( GLint x, GLint y, GLsizei width, GLsizei height )
392 {
393 GET_CURRENT_CONTEXT(ctx);
394 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
395 _mesa_set_viewport(ctx, x, y, width, height);
396 }
397
398
399 /*
400 * Define a new viewport and reallocate auxillary buffers if the size of
401 * the window (color buffer) has changed.
402 */
403 void
404 _mesa_set_viewport( GLcontext *ctx, GLint x, GLint y,
405 GLsizei width, GLsizei height )
406 {
407 const GLfloat n = ctx->Viewport.Near;
408 const GLfloat f = ctx->Viewport.Far;
409
410 if (width < 0 || height < 0) {
411 _mesa_error( ctx, GL_INVALID_VALUE, "glViewport" );
412 return;
413 }
414
415 if (MESA_VERBOSE & VERBOSE_API)
416 _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
417
418 /* clamp width, and height to implementation dependent range */
419 width = CLAMP( width, 1, MAX_WIDTH );
420 height = CLAMP( height, 1, MAX_HEIGHT );
421
422 /* Save viewport */
423 ctx->Viewport.X = x;
424 ctx->Viewport.Width = width;
425 ctx->Viewport.Y = y;
426 ctx->Viewport.Height = height;
427
428 /* compute scale and bias values :: This is really driver-specific
429 * and should be maintained elsewhere if at all.
430 */
431 ctx->Viewport._WindowMap.m[MAT_SX] = (GLfloat) width / 2.0F;
432 ctx->Viewport._WindowMap.m[MAT_TX] = ctx->Viewport._WindowMap.m[MAT_SX] + x;
433 ctx->Viewport._WindowMap.m[MAT_SY] = (GLfloat) height / 2.0F;
434 ctx->Viewport._WindowMap.m[MAT_TY] = ctx->Viewport._WindowMap.m[MAT_SY] + y;
435 ctx->Viewport._WindowMap.m[MAT_SZ] = ctx->DepthMaxF * ((f - n) / 2.0F);
436 ctx->Viewport._WindowMap.m[MAT_TZ] = ctx->DepthMaxF * ((f - n) / 2.0F + n);
437 ctx->Viewport._WindowMap.flags = MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION;
438 ctx->Viewport._WindowMap.type = MATRIX_3D_NO_ROT;
439 ctx->NewState |= _NEW_VIEWPORT;
440
441 /* Check if window/buffer has been resized and if so, reallocate the
442 * ancillary buffers.
443 */
444 _mesa_ResizeBuffersMESA();
445
446 if (ctx->Driver.Viewport) {
447 (*ctx->Driver.Viewport)( ctx, x, y, width, height );
448 }
449 }
450
451
452
453 void
454 _mesa_DepthRange( GLclampd nearval, GLclampd farval )
455 {
456 /*
457 * nearval - specifies mapping of the near clipping plane to window
458 * coordinates, default is 0
459 * farval - specifies mapping of the far clipping plane to window
460 * coordinates, default is 1
461 *
462 * After clipping and div by w, z coords are in -1.0 to 1.0,
463 * corresponding to near and far clipping planes. glDepthRange
464 * specifies a linear mapping of the normalized z coords in
465 * this range to window z coords.
466 */
467 GLfloat n, f;
468 GET_CURRENT_CONTEXT(ctx);
469 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
470
471 if (MESA_VERBOSE&VERBOSE_API)
472 _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
473
474 n = (GLfloat) CLAMP( nearval, 0.0, 1.0 );
475 f = (GLfloat) CLAMP( farval, 0.0, 1.0 );
476
477 ctx->Viewport.Near = n;
478 ctx->Viewport.Far = f;
479 ctx->Viewport._WindowMap.m[MAT_SZ] = ctx->DepthMaxF * ((f - n) / 2.0F);
480 ctx->Viewport._WindowMap.m[MAT_TZ] = ctx->DepthMaxF * ((f - n) / 2.0F + n);
481 ctx->NewState |= _NEW_VIEWPORT;
482
483 if (ctx->Driver.DepthRange) {
484 (*ctx->Driver.DepthRange)( ctx, nearval, farval );
485 }
486 }