7d2f74cfb209538a38b7340c8385dda0837176af
[mesa.git] / src / glu / mesa / glu.c
1 /* $Id: glu.c,v 1.11 1999/09/17 01:00:38 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 * Copyright (C) 1995-1999 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 /*
25 * $Log: glu.c,v $
26 * Revision 1.11 1999/09/17 01:00:38 brianp
27 * fixed typo
28 *
29 * Revision 1.10 1999/09/17 00:06:14 brianp
30 * gluGetProcAddressEXT change for C++ / BeOS
31 *
32 * Revision 1.9 1999/09/16 22:37:56 brianp
33 * added some casts in gluGetProcAddressEXT()
34 *
35 * Revision 1.8 1999/09/16 16:53:28 brianp
36 * clean-up of GLU_EXT_get_proc_address
37 *
38 * Revision 1.7 1999/09/14 00:11:40 brianp
39 * added gluCheckExtension()
40 *
41 * Revision 1.6 1999/09/13 14:31:32 joukj
42 *
43 * strcmp needs the string.h
44 *
45 * Revision 1.5 1999/09/11 12:04:54 brianp
46 * added 1.2 function to gluGetProcAddressEXT()
47 *
48 * Revision 1.4 1999/09/11 11:36:26 brianp
49 * added GLU_EXT_get_proc_address
50 *
51 * Revision 1.3 1999/09/10 04:32:10 gareth
52 * Fixed triangle output, recovery process termination.
53 *
54 * Revision 1.2 1999/09/10 02:03:31 gareth
55 * Added GLU 1.3 tessellation (except winding rule code).
56 *
57 * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
58 * Imported sources
59 *
60 * Revision 1.13 1999/03/31 19:07:28 brianp
61 * added GL_EXT_abgr to extensions
62 *
63 * Revision 1.12 1999/02/06 06:12:41 brianp
64 * updated version string to 3.1
65 *
66 * Revision 1.11 1999/01/03 03:23:15 brianp
67 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
68 *
69 * Revision 1.10 1998/04/22 00:35:50 brianp
70 * changed version to 3.0
71 *
72 * Revision 1.9 1997/12/09 03:03:32 brianp
73 * changed version to 2.6
74 *
75 * Revision 1.8 1997/10/04 01:30:20 brianp
76 * changed version to 2.5
77 *
78 * Revision 1.7 1997/08/13 01:25:21 brianp
79 * changed version string to 2.4
80 *
81 * Revision 1.6 1997/07/24 01:28:44 brianp
82 * changed precompiled header symbol from PCH to PC_HEADER
83 *
84 * Revision 1.5 1997/07/13 22:59:11 brianp
85 * added const to viewport parameter of gluPickMatrix()
86 *
87 * Revision 1.4 1997/05/28 02:29:38 brianp
88 * added support for precompiled headers (PCH), inserted APIENTRY keyword
89 *
90 * Revision 1.3 1997/04/12 16:19:02 brianp
91 * changed version to 2.3
92 *
93 * Revision 1.2 1997/03/11 00:58:34 brianp
94 * changed version to 2.2
95 *
96 * Revision 1.1 1996/09/27 01:19:39 brianp
97 * Initial revision
98 *
99 */
100
101
102 #ifdef PC_HEADER
103 #include "all.h"
104 #else
105 #include <assert.h>
106 #include <math.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include "gluP.h"
111 #endif
112
113
114 /*
115 * Miscellaneous utility functions
116 */
117
118
119 #ifndef M_PI
120 #define M_PI 3.1415926536
121 #endif
122 #define EPS 0.00001
123
124
125
126
127 void GLAPIENTRY gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
128 GLdouble centerx, GLdouble centery, GLdouble centerz,
129 GLdouble upx, GLdouble upy, GLdouble upz )
130 {
131 GLdouble m[16];
132 GLdouble x[3], y[3], z[3];
133 GLdouble mag;
134
135 /* Make rotation matrix */
136
137 /* Z vector */
138 z[0] = eyex - centerx;
139 z[1] = eyey - centery;
140 z[2] = eyez - centerz;
141 mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
142 if (mag) { /* mpichler, 19950515 */
143 z[0] /= mag;
144 z[1] /= mag;
145 z[2] /= mag;
146 }
147
148 /* Y vector */
149 y[0] = upx;
150 y[1] = upy;
151 y[2] = upz;
152
153 /* X vector = Y cross Z */
154 x[0] = y[1]*z[2] - y[2]*z[1];
155 x[1] = -y[0]*z[2] + y[2]*z[0];
156 x[2] = y[0]*z[1] - y[1]*z[0];
157
158 /* Recompute Y = Z cross X */
159 y[0] = z[1]*x[2] - z[2]*x[1];
160 y[1] = -z[0]*x[2] + z[2]*x[0];
161 y[2] = z[0]*x[1] - z[1]*x[0];
162
163 /* mpichler, 19950515 */
164 /* cross product gives area of parallelogram, which is < 1.0 for
165 * non-perpendicular unit-length vectors; so normalize x, y here
166 */
167
168 mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
169 if (mag) {
170 x[0] /= mag;
171 x[1] /= mag;
172 x[2] /= mag;
173 }
174
175 mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
176 if (mag) {
177 y[0] /= mag;
178 y[1] /= mag;
179 y[2] /= mag;
180 }
181
182 #define M(row,col) m[col*4+row]
183 M(0,0) = x[0]; M(0,1) = x[1]; M(0,2) = x[2]; M(0,3) = 0.0;
184 M(1,0) = y[0]; M(1,1) = y[1]; M(1,2) = y[2]; M(1,3) = 0.0;
185 M(2,0) = z[0]; M(2,1) = z[1]; M(2,2) = z[2]; M(2,3) = 0.0;
186 M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
187 #undef M
188 glMultMatrixd( m );
189
190 /* Translate Eye to Origin */
191 glTranslated( -eyex, -eyey, -eyez );
192
193 }
194
195
196
197 void GLAPIENTRY gluOrtho2D( GLdouble left, GLdouble right,
198 GLdouble bottom, GLdouble top )
199 {
200 glOrtho( left, right, bottom, top, -1.0, 1.0 );
201 }
202
203
204
205 void GLAPIENTRY gluPerspective( GLdouble fovy, GLdouble aspect,
206 GLdouble zNear, GLdouble zFar )
207 {
208 GLdouble xmin, xmax, ymin, ymax;
209
210 ymax = zNear * tan( fovy * M_PI / 360.0 );
211 ymin = -ymax;
212
213 xmin = ymin * aspect;
214 xmax = ymax * aspect;
215
216 glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
217 }
218
219
220
221 void GLAPIENTRY gluPickMatrix( GLdouble x, GLdouble y,
222 GLdouble width, GLdouble height,
223 const GLint viewport[4] )
224 {
225 GLfloat m[16];
226 GLfloat sx, sy;
227 GLfloat tx, ty;
228
229 sx = viewport[2] / width;
230 sy = viewport[3] / height;
231 tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
232 ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
233
234 #define M(row,col) m[col*4+row]
235 M(0,0) = sx; M(0,1) = 0.0; M(0,2) = 0.0; M(0,3) = tx;
236 M(1,0) = 0.0; M(1,1) = sy; M(1,2) = 0.0; M(1,3) = ty;
237 M(2,0) = 0.0; M(2,1) = 0.0; M(2,2) = 1.0; M(2,3) = 0.0;
238 M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
239 #undef M
240
241 glMultMatrixf( m );
242 }
243
244
245
246 const GLubyte* GLAPIENTRY gluErrorString( GLenum errorCode )
247 {
248 static char *tess_error[] = {
249 "missing gluBeginPolygon",
250 "missing gluBeginContour",
251 "missing gluEndPolygon",
252 "missing gluEndContour",
253 "misoriented or self-intersecting loops",
254 "coincident vertices",
255 "colinear vertices",
256 "FIST recovery process fatal error"
257 };
258 static char *nurbs_error[] = {
259 "spline order un-supported",
260 "too few knots",
261 "valid knot range is empty",
262 "decreasing knot sequence knot",
263 "knot multiplicity greater than order of spline",
264 "endcurve() must follow bgncurve()",
265 "bgncurve() must precede endcurve()",
266 "missing or extra geometric data",
267 "can't draw pwlcurves",
268 "missing bgncurve()",
269 "missing bgnsurface()",
270 "endtrim() must precede endsurface()",
271 "bgnsurface() must precede endsurface()",
272 "curve of improper type passed as trim curve",
273 "bgnsurface() must precede bgntrim()",
274 "endtrim() must follow bgntrim()",
275 "bgntrim() must precede endtrim()",
276 "invalid or missing trim curve",
277 "bgntrim() must precede pwlcurve()",
278 "pwlcurve referenced twice",
279 "pwlcurve and nurbscurve mixed",
280 "improper usage of trim data type",
281 "nurbscurve referenced twice",
282 "nurbscurve and pwlcurve mixed",
283 "nurbssurface referenced twice",
284 "invalid property",
285 "endsurface() must follow bgnsurface()",
286 "misoriented trim curves",
287 "intersecting trim curves",
288 "UNUSED",
289 "unconnected trim curves",
290 "unknown knot error",
291 "negative vertex count encountered",
292 "negative byte-stride encounteed",
293 "unknown type descriptor",
294 "null control array or knot vector",
295 "duplicate point on pwlcurve"
296 };
297
298 /* GL Errors */
299 if (errorCode==GL_NO_ERROR) {
300 return (GLubyte *) "no error";
301 }
302 else if (errorCode==GL_INVALID_VALUE) {
303 return (GLubyte *) "invalid value";
304 }
305 else if (errorCode==GL_INVALID_ENUM) {
306 return (GLubyte *) "invalid enum";
307 }
308 else if (errorCode==GL_INVALID_OPERATION) {
309 return (GLubyte *) "invalid operation";
310 }
311 else if (errorCode==GL_STACK_OVERFLOW) {
312 return (GLubyte *) "stack overflow";
313 }
314 else if (errorCode==GL_STACK_UNDERFLOW) {
315 return (GLubyte *) "stack underflow";
316 }
317 else if (errorCode==GL_OUT_OF_MEMORY) {
318 return (GLubyte *) "out of memory";
319 }
320 /* GLU Errors */
321 else if (errorCode==GLU_NO_ERROR) {
322 return (GLubyte *) "no error";
323 }
324 else if (errorCode==GLU_INVALID_ENUM) {
325 return (GLubyte *) "invalid enum";
326 }
327 else if (errorCode==GLU_INVALID_VALUE) {
328 return (GLubyte *) "invalid value";
329 }
330 else if (errorCode==GLU_OUT_OF_MEMORY) {
331 return (GLubyte *) "out of memory";
332 }
333 else if (errorCode==GLU_INCOMPATIBLE_GL_VERSION) {
334 return (GLubyte *) "incompatible GL version";
335 }
336 else if (errorCode>=GLU_TESS_ERROR1 && errorCode<=GLU_TESS_ERROR8) {
337 return (GLubyte *) tess_error[errorCode-GLU_TESS_ERROR1];
338 }
339 else if (errorCode>=GLU_NURBS_ERROR1 && errorCode<=GLU_NURBS_ERROR37) {
340 return (GLubyte *) nurbs_error[errorCode-GLU_NURBS_ERROR1];
341 }
342 else {
343 return NULL;
344 }
345 }
346
347
348
349 /*
350 * New in GLU 1.1
351 */
352
353 const GLubyte* GLAPIENTRY gluGetString( GLenum name )
354 {
355 static char *extensions = "GL_EXT_abgr GLU_EXT_get_proc_address";
356 static char *version = "1.2 Mesa 3.1";
357
358 switch (name) {
359 case GLU_EXTENSIONS:
360 return (GLubyte *) extensions;
361 case GLU_VERSION:
362 return (GLubyte *) version;
363 default:
364 return NULL;
365 }
366 }
367
368
369
370 #ifdef GLU_EXT_get_proc_address
371
372 #ifdef __cplusplus
373 /* for BeOS R4.5 */
374 void GLAPIENTRY (*gluGetProcAddressEXT(const GLubyte *procName))(...)
375 #else
376 void GLAPIENTRY (*gluGetProcAddressEXT(const GLubyte *procName))()
377 #endif
378 {
379 struct proc {
380 const char *name;
381 void *address;
382 };
383 static struct proc procTable[] = {
384 { "gluGetProcAddressEXT", (void *) gluGetProcAddressEXT }, /* me! */
385
386 /* new 1.1 functions */
387 { "gluGetString", (void *) gluGetString },
388
389 /* new 1.2 functions */
390 { "gluTessBeginPolygon", (void *) gluTessBeginPolygon },
391 { "gluTessBeginContour", (void *) gluTessBeginContour },
392 { "gluTessEndContour", (void *) gluTessEndContour },
393 { "gluTessEndPolygon", (void *) gluTessEndPolygon },
394 { "gluGetTessProperty", (void *) gluGetTessProperty },
395
396 /* new 1.3 functions */
397
398 { NULL, NULL }
399 };
400 GLuint i;
401
402 for (i = 0; procTable[i].address; i++) {
403 if (strcmp((const char *) procName, procTable[i].name) == 0)
404 return (void (*)()) procTable[i].address;
405 }
406
407 return NULL;
408 }
409
410 #endif
411
412
413
414 /*
415 * New in GLU 1.3
416 */
417 GLboolean GLAPIENTRY
418 gluCheckExtension( const char *extName, const GLubyte *extString )
419 {
420 assert(extName);
421 assert(extString);
422 {
423 const int len = strlen(extName);
424 const char *start = (const char *) extString;
425
426 while (1) {
427 const char *c = strstr( start, extName );
428 if (!c)
429 return GL_FALSE;
430
431 if ((c == start || c[-1] == ' ') && (c[len] == ' ' || c[len] == 0))
432 return GL_TRUE;
433
434 start = c + len;
435 }
436 }
437 }