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