patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / glu / mini / glu.c
1 /* $Id: glu.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 * Copyright (C) 1995-2001 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 #ifdef PC_HEADER
25 #include "all.h"
26 #else
27 #include <assert.h>
28 #include <math.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "gluP.h"
33 #endif
34
35
36 /*
37 * Miscellaneous utility functions
38 */
39
40
41 #ifndef M_PI
42 #define M_PI 3.1415926536
43 #endif
44 #define EPS 0.00001
45
46 #ifndef GLU_INCOMPATIBLE_GL_VERSION
47 #define GLU_INCOMPATIBLE_GL_VERSION 100903
48 #endif
49
50
51 void GLAPIENTRY
52 gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
53 GLdouble centerx, GLdouble centery, GLdouble centerz,
54 GLdouble upx, GLdouble upy, GLdouble upz)
55 {
56 GLfloat m[16];
57 GLfloat x[3], y[3], z[3];
58 GLfloat mag;
59
60 /* Make rotation matrix */
61
62 /* Z vector */
63 z[0] = eyex - centerx;
64 z[1] = eyey - centery;
65 z[2] = eyez - centerz;
66 mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
67 if (mag) { /* mpichler, 19950515 */
68 z[0] /= mag;
69 z[1] /= mag;
70 z[2] /= mag;
71 }
72
73 /* Y vector */
74 y[0] = upx;
75 y[1] = upy;
76 y[2] = upz;
77
78 /* X vector = Y cross Z */
79 x[0] = y[1] * z[2] - y[2] * z[1];
80 x[1] = -y[0] * z[2] + y[2] * z[0];
81 x[2] = y[0] * z[1] - y[1] * z[0];
82
83 /* Recompute Y = Z cross X */
84 y[0] = z[1] * x[2] - z[2] * x[1];
85 y[1] = -z[0] * x[2] + z[2] * x[0];
86 y[2] = z[0] * x[1] - z[1] * x[0];
87
88 /* mpichler, 19950515 */
89 /* cross product gives area of parallelogram, which is < 1.0 for
90 * non-perpendicular unit-length vectors; so normalize x, y here
91 */
92
93 mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
94 if (mag) {
95 x[0] /= mag;
96 x[1] /= mag;
97 x[2] /= mag;
98 }
99
100 mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
101 if (mag) {
102 y[0] /= mag;
103 y[1] /= mag;
104 y[2] /= mag;
105 }
106
107 #define M(row,col) m[col*4+row]
108 M(0, 0) = x[0];
109 M(0, 1) = x[1];
110 M(0, 2) = x[2];
111 M(0, 3) = 0.0;
112 M(1, 0) = y[0];
113 M(1, 1) = y[1];
114 M(1, 2) = y[2];
115 M(1, 3) = 0.0;
116 M(2, 0) = z[0];
117 M(2, 1) = z[1];
118 M(2, 2) = z[2];
119 M(2, 3) = 0.0;
120 M(3, 0) = 0.0;
121 M(3, 1) = 0.0;
122 M(3, 2) = 0.0;
123 M(3, 3) = 1.0;
124 #undef M
125 glMultMatrixf(m);
126
127 /* Translate Eye to Origin */
128 glTranslatef(-eyex, -eyey, -eyez);
129
130 }
131
132
133
134 void GLAPIENTRY
135 gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
136 {
137 glOrtho(left, right, bottom, top, -1.0, 1.0);
138 }
139
140
141
142 static void
143 frustum(GLfloat left, GLfloat right,
144 GLfloat bottom, GLfloat top,
145 GLfloat nearval, GLfloat farval)
146 {
147 GLfloat x, y, a, b, c, d;
148 GLfloat m[16];
149
150 x = (2.0 * nearval) / (right - left);
151 y = (2.0 * nearval) / (top - bottom);
152 a = (right + left) / (right - left);
153 b = (top + bottom) / (top - bottom);
154 c = -(farval + nearval) / ( farval - nearval);
155 d = -(2.0 * farval * nearval) / (farval - nearval);
156
157 #define M(row,col) m[col*4+row]
158 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
159 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
160 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
161 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
162 #undef M
163
164 glMultMatrixf(m);
165 }
166
167
168 void GLAPIENTRY
169 gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
170 {
171 GLfloat xmin, xmax, ymin, ymax;
172
173 ymax = zNear * tan(fovy * M_PI / 360.0);
174 ymin = -ymax;
175 xmin = ymin * aspect;
176 xmax = ymax * aspect;
177
178 /* don't call glFrustum() because of error semantics (covglu) */
179 frustum(xmin, xmax, ymin, ymax, zNear, zFar);
180 }
181
182
183
184 void GLAPIENTRY
185 gluPickMatrix(GLdouble x, GLdouble y,
186 GLdouble width, GLdouble height, GLint viewport[4])
187 {
188 GLfloat m[16];
189 GLfloat sx, sy;
190 GLfloat tx, ty;
191
192 sx = viewport[2] / width;
193 sy = viewport[3] / height;
194 tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
195 ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
196
197 #define M(row,col) m[col*4+row]
198 M(0, 0) = sx;
199 M(0, 1) = 0.0;
200 M(0, 2) = 0.0;
201 M(0, 3) = tx;
202 M(1, 0) = 0.0;
203 M(1, 1) = sy;
204 M(1, 2) = 0.0;
205 M(1, 3) = ty;
206 M(2, 0) = 0.0;
207 M(2, 1) = 0.0;
208 M(2, 2) = 1.0;
209 M(2, 3) = 0.0;
210 M(3, 0) = 0.0;
211 M(3, 1) = 0.0;
212 M(3, 2) = 0.0;
213 M(3, 3) = 1.0;
214 #undef M
215
216 glMultMatrixf(m);
217 }
218
219
220
221 const GLubyte *GLAPIENTRY
222 gluErrorString(GLenum errorCode)
223 {
224 static char *tess_error[] = {
225 "missing gluBeginPolygon",
226 "missing gluBeginContour",
227 "missing gluEndPolygon",
228 "missing gluEndContour",
229 "misoriented or self-intersecting loops",
230 "coincident vertices",
231 "colinear vertices",
232 "FIST recovery process fatal error"
233 };
234 static char *nurbs_error[] = {
235 "spline order un-supported",
236 "too few knots",
237 "valid knot range is empty",
238 "decreasing knot sequence knot",
239 "knot multiplicity greater than order of spline",
240 "endcurve() must follow bgncurve()",
241 "bgncurve() must precede endcurve()",
242 "missing or extra geometric data",
243 "can't draw pwlcurves",
244 "missing bgncurve()",
245 "missing bgnsurface()",
246 "endtrim() must precede endsurface()",
247 "bgnsurface() must precede endsurface()",
248 "curve of improper type passed as trim curve",
249 "bgnsurface() must precede bgntrim()",
250 "endtrim() must follow bgntrim()",
251 "bgntrim() must precede endtrim()",
252 "invalid or missing trim curve",
253 "bgntrim() must precede pwlcurve()",
254 "pwlcurve referenced twice",
255 "pwlcurve and nurbscurve mixed",
256 "improper usage of trim data type",
257 "nurbscurve referenced twice",
258 "nurbscurve and pwlcurve mixed",
259 "nurbssurface referenced twice",
260 "invalid property",
261 "endsurface() must follow bgnsurface()",
262 "misoriented trim curves",
263 "intersecting trim curves",
264 "UNUSED",
265 "unconnected trim curves",
266 "unknown knot error",
267 "negative vertex count encountered",
268 "negative byte-stride encountered",
269 "unknown type descriptor",
270 "null control array or knot vector",
271 "duplicate point on pwlcurve"
272 };
273
274 /* GL Errors */
275 if (errorCode == GL_NO_ERROR) {
276 return (GLubyte *) "no error";
277 }
278 else if (errorCode == GL_INVALID_VALUE) {
279 return (GLubyte *) "invalid value";
280 }
281 else if (errorCode == GL_INVALID_ENUM) {
282 return (GLubyte *) "invalid enum";
283 }
284 else if (errorCode == GL_INVALID_OPERATION) {
285 return (GLubyte *) "invalid operation";
286 }
287 else if (errorCode == GL_STACK_OVERFLOW) {
288 return (GLubyte *) "stack overflow";
289 }
290 else if (errorCode == GL_STACK_UNDERFLOW) {
291 return (GLubyte *) "stack underflow";
292 }
293 else if (errorCode == GL_OUT_OF_MEMORY) {
294 return (GLubyte *) "out of memory";
295 }
296 /* GLU Errors */
297 else if (errorCode == GLU_NO_ERROR) {
298 return (GLubyte *) "no error";
299 }
300 else if (errorCode == GLU_INVALID_ENUM) {
301 return (GLubyte *) "invalid enum";
302 }
303 else if (errorCode == GLU_INVALID_VALUE) {
304 return (GLubyte *) "invalid value";
305 }
306 else if (errorCode == GLU_OUT_OF_MEMORY) {
307 return (GLubyte *) "out of memory";
308 }
309 else if (errorCode == GLU_INCOMPATIBLE_GL_VERSION) {
310 return (GLubyte *) "incompatible GL version";
311 }
312 else if (errorCode >= GLU_TESS_ERROR1 && errorCode <= GLU_TESS_ERROR8) {
313 return (GLubyte *) tess_error[errorCode - GLU_TESS_ERROR1];
314 }
315 else if (errorCode >= GLU_NURBS_ERROR1 && errorCode <= GLU_NURBS_ERROR37) {
316 return (GLubyte *) nurbs_error[errorCode - GLU_NURBS_ERROR1];
317 }
318 else {
319 return NULL;
320 }
321 }
322
323
324
325 /*
326 * New in GLU 1.1
327 */
328
329 const GLubyte *GLAPIENTRY
330 gluGetString(GLenum name)
331 {
332 static char *extensions = "GL_EXT_abgr";
333 static char *version = "1.1 Mesa 3.5";
334
335 switch (name) {
336 case GLU_EXTENSIONS:
337 return (GLubyte *) extensions;
338 case GLU_VERSION:
339 return (GLubyte *) version;
340 default:
341 return NULL;
342 }
343 }
344
345
346
347 #if 0 /* gluGetProcAddressEXT not finalized yet! */
348
349 #ifdef __cplusplus
350 /* for BeOS R4.5 */
351 void GLAPIENTRY(*gluGetProcAddressEXT(const GLubyte * procName)) (...)
352 #else
353 void (GLAPIENTRY * gluGetProcAddressEXT(const GLubyte * procName)) ()
354 #endif
355 {
356 struct proc
357 {
358 const char *name;
359 void *address;
360 };
361 static struct proc procTable[] = {
362 {"gluGetProcAddressEXT", (void *) gluGetProcAddressEXT}, /* me! */
363
364 /* new 1.1 functions */
365 {"gluGetString", (void *) gluGetString},
366
367 /* new 1.2 functions */
368 {"gluTessBeginPolygon", (void *) gluTessBeginPolygon},
369 {"gluTessBeginContour", (void *) gluTessBeginContour},
370 {"gluTessEndContour", (void *) gluTessEndContour},
371 {"gluTessEndPolygon", (void *) gluTessEndPolygon},
372 {"gluGetTessProperty", (void *) gluGetTessProperty},
373
374 /* new 1.3 functions */
375
376 {NULL, NULL}
377 };
378 GLuint i;
379
380 for (i = 0; procTable[i].address; i++) {
381 if (strcmp((const char *) procName, procTable[i].name) == 0)
382 return (void (GLAPIENTRY *) ()) procTable[i].address;
383 }
384
385 return NULL;
386 }
387
388 #endif
389
390
391
392 /*
393 * New in GLU 1.3
394 */
395 #ifdef GLU_VERSION_1_3
396 GLboolean GLAPIENTRY
397 gluCheckExtension(const GLubyte *extName, const GLubyte * extString)
398 {
399 assert(extName);
400 assert(extString);
401 {
402 const int len = strlen((const char *) extName);
403 const char *start = (const char *) extString;
404
405 while (1) {
406 const char *c = strstr(start, (const char *) extName);
407 if (!c)
408 return GL_FALSE;
409
410 if ((c == start || c[-1] == ' ') && (c[len] == ' ' || c[len] == 0))
411 return GL_TRUE;
412
413 start = c + len;
414 }
415 }
416 }
417 #endif