glu/sgi: Initialize members of class Arc.
[mesa.git] / src / glu / mesa / nurbscrv.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 3.3
5 * Copyright (C) 1995-2000 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 /*
24 * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
25 * See README2 for more info.
26 */
27
28
29 #ifdef PC_HEADER
30 #include "all.h"
31 #else
32 #include <math.h>
33 #include <stdlib.h>
34 #include "gluP.h"
35 #include "nurbs.h"
36 #endif
37
38
39 static int
40 get_curve_dim(GLenum type)
41 {
42 switch (type) {
43 case GL_MAP1_VERTEX_3:
44 return 3;
45 case GL_MAP1_VERTEX_4:
46 return 4;
47 case GL_MAP1_INDEX:
48 return 1;
49 case GL_MAP1_COLOR_4:
50 return 4;
51 case GL_MAP1_NORMAL:
52 return 3;
53 case GL_MAP1_TEXTURE_COORD_1:
54 return 1;
55 case GL_MAP1_TEXTURE_COORD_2:
56 return 2;
57 case GL_MAP1_TEXTURE_COORD_3:
58 return 3;
59 case GL_MAP1_TEXTURE_COORD_4:
60 return 4;
61 default:
62 abort(); /* TODO: is this OK? */
63 }
64 return 0; /*never get here */
65 }
66
67 static GLenum
68 test_nurbs_curve(GLUnurbsObj * nobj, curve_attribs * attribs)
69 {
70 GLenum err;
71 GLint tmp_int;
72
73 if (attribs->order < 0) {
74 call_user_error(nobj, GLU_INVALID_VALUE);
75 return GLU_ERROR;
76 }
77 glGetIntegerv(GL_MAX_EVAL_ORDER, &tmp_int);
78 if (attribs->order > tmp_int || attribs->order < 2) {
79 call_user_error(nobj, GLU_NURBS_ERROR1);
80 return GLU_ERROR;
81 }
82 if (attribs->knot_count < attribs->order + 2) {
83 call_user_error(nobj, GLU_NURBS_ERROR2);
84 return GLU_ERROR;
85 }
86 if (attribs->stride < 0) {
87 call_user_error(nobj, GLU_NURBS_ERROR34);
88 return GLU_ERROR;
89 }
90 if (attribs->knot == NULL || attribs->ctrlarray == NULL) {
91 call_user_error(nobj, GLU_NURBS_ERROR36);
92 return GLU_ERROR;
93 }
94 if ((err = test_knot(attribs->knot_count, attribs->knot, attribs->order))
95 != GLU_NO_ERROR) {
96 call_user_error(nobj, err);
97 return GLU_ERROR;
98 }
99 return GLU_NO_ERROR;
100 }
101
102 static GLenum
103 test_nurbs_curves(GLUnurbsObj * nobj)
104 {
105 /* test the geometric data */
106 if (test_nurbs_curve(nobj, &(nobj->curve.geom)) != GLU_NO_ERROR)
107 return GLU_ERROR;
108 /* now test the attributive data */
109 /* color */
110 if (nobj->curve.color.type != GLU_INVALID_ENUM)
111 if (test_nurbs_curve(nobj, &(nobj->curve.color)) != GLU_NO_ERROR)
112 return GLU_ERROR;
113 /* normal */
114 if (nobj->curve.normal.type != GLU_INVALID_ENUM)
115 if (test_nurbs_curve(nobj, &(nobj->curve.normal)) != GLU_NO_ERROR)
116 return GLU_ERROR;
117 /* texture */
118 if (nobj->curve.texture.type != GLU_INVALID_ENUM)
119 if (test_nurbs_curve(nobj, &(nobj->curve.texture)) != GLU_NO_ERROR)
120 return GLU_ERROR;
121 return GLU_NO_ERROR;
122 }
123
124 /* prepare the knot information structures */
125 static GLenum
126 fill_knot_structures(GLUnurbsObj * nobj, knot_str_type * geom_knot,
127 knot_str_type * color_knot, knot_str_type * normal_knot,
128 knot_str_type * texture_knot)
129 {
130 GLint order;
131 GLfloat *knot;
132 GLint nknots;
133 GLint t_min, t_max;
134
135 geom_knot->unified_knot = NULL;
136 knot = geom_knot->knot = nobj->curve.geom.knot;
137 nknots = geom_knot->nknots = nobj->curve.geom.knot_count;
138 order = geom_knot->order = nobj->curve.geom.order;
139 geom_knot->delta_nknots = 0;
140 t_min = geom_knot->t_min = order - 1;
141 t_max = geom_knot->t_max = nknots - order;
142 if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
143 call_user_error(nobj, GLU_NURBS_ERROR3);
144 return GLU_ERROR;
145 }
146 if (fabs(knot[0] - knot[t_min]) < EPSILON) {
147 /* knot open at beggining */
148 geom_knot->open_at_begin = GL_TRUE;
149 }
150 else
151 geom_knot->open_at_begin = GL_FALSE;
152 if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
153 /* knot open at end */
154 geom_knot->open_at_end = GL_TRUE;
155 }
156 else
157 geom_knot->open_at_end = GL_FALSE;
158 if (nobj->curve.color.type != GLU_INVALID_ENUM) {
159 color_knot->unified_knot = (GLfloat *) 1;
160 knot = color_knot->knot = nobj->curve.color.knot;
161 nknots = color_knot->nknots = nobj->curve.color.knot_count;
162 order = color_knot->order = nobj->curve.color.order;
163 color_knot->delta_nknots = 0;
164 t_min = color_knot->t_min = order - 1;
165 t_max = color_knot->t_max = nknots - order;
166 if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
167 call_user_error(nobj, GLU_NURBS_ERROR3);
168 return GLU_ERROR;
169 }
170 if (fabs(knot[0] - knot[t_min]) < EPSILON) {
171 /* knot open at beggining */
172 color_knot->open_at_begin = GL_TRUE;
173 }
174 else
175 color_knot->open_at_begin = GL_FALSE;
176 if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
177 /* knot open at end */
178 color_knot->open_at_end = GL_TRUE;
179 }
180 else
181 color_knot->open_at_end = GL_FALSE;
182 }
183 else
184 color_knot->unified_knot = NULL;
185 if (nobj->curve.normal.type != GLU_INVALID_ENUM) {
186 normal_knot->unified_knot = (GLfloat *) 1;
187 knot = normal_knot->knot = nobj->curve.normal.knot;
188 nknots = normal_knot->nknots = nobj->curve.normal.knot_count;
189 order = normal_knot->order = nobj->curve.normal.order;
190 normal_knot->delta_nknots = 0;
191 t_min = normal_knot->t_min = order - 1;
192 t_max = normal_knot->t_max = nknots - order;
193 if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
194 call_user_error(nobj, GLU_NURBS_ERROR3);
195 return GLU_ERROR;
196 }
197 if (fabs(knot[0] - knot[t_min]) < EPSILON) {
198 /* knot open at beggining */
199 normal_knot->open_at_begin = GL_TRUE;
200 }
201 else
202 normal_knot->open_at_begin = GL_FALSE;
203 if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
204 /* knot open at end */
205 normal_knot->open_at_end = GL_TRUE;
206 }
207 else
208 normal_knot->open_at_end = GL_FALSE;
209 }
210 else
211 normal_knot->unified_knot = NULL;
212 if (nobj->curve.texture.type != GLU_INVALID_ENUM) {
213 texture_knot->unified_knot = (GLfloat *) 1;
214 knot = texture_knot->knot = nobj->curve.texture.knot;
215 nknots = texture_knot->nknots = nobj->curve.texture.knot_count;
216 order = texture_knot->order = nobj->curve.texture.order;
217 texture_knot->delta_nknots = 0;
218 t_min = texture_knot->t_min = order - 1;
219 t_max = texture_knot->t_max = nknots - order;
220 if (fabs(knot[t_min] - knot[t_max]) < EPSILON) {
221 call_user_error(nobj, GLU_NURBS_ERROR3);
222 return GLU_ERROR;
223 }
224 if (fabs(knot[0] - knot[t_min]) < EPSILON) {
225 /* knot open at beggining */
226 texture_knot->open_at_begin = GL_TRUE;
227 }
228 else
229 texture_knot->open_at_begin = GL_FALSE;
230 if (fabs(knot[t_max] - knot[nknots - 1]) < EPSILON) {
231 /* knot open at end */
232 texture_knot->open_at_end = GL_TRUE;
233 }
234 else
235 texture_knot->open_at_end = GL_FALSE;
236 }
237 else
238 texture_knot->unified_knot = NULL;
239 return GLU_NO_ERROR;
240 }
241
242 /* covert the NURBS curve into a series of adjacent Bezier curves */
243 static GLenum
244 convert_curve(knot_str_type * the_knot, curve_attribs * attrib,
245 GLfloat ** new_ctrl, GLint * ncontrol)
246 {
247 GLenum err;
248
249 if ((err = explode_knot(the_knot)) != GLU_NO_ERROR) {
250 if (the_knot->unified_knot) {
251 free(the_knot->unified_knot);
252 the_knot->unified_knot = NULL;
253 }
254 return err;
255 }
256 if (the_knot->unified_knot) {
257 free(the_knot->unified_knot);
258 the_knot->unified_knot = NULL;
259 }
260 if ((err = calc_alphas(the_knot)) != GLU_NO_ERROR) {
261 free(the_knot->new_knot);
262 return err;
263 }
264 free(the_knot->new_knot);
265 if ((err = calc_new_ctrl_pts(attrib->ctrlarray, attrib->stride, the_knot,
266 attrib->dim, new_ctrl, ncontrol))
267 != GLU_NO_ERROR) {
268 free(the_knot->alpha);
269 return err;
270 }
271 free(the_knot->alpha);
272 return GLU_NO_ERROR;
273 }
274
275 /* covert curves - geometry and possible attribute ones into equivalent */
276 /* sequence of adjacent Bezier curves */
277 static GLenum
278 convert_curves(GLUnurbsObj * nobj, GLfloat ** new_geom_ctrl,
279 GLint * ncontrol, GLfloat ** new_color_ctrl,
280 GLfloat ** new_normal_ctrl, GLfloat ** new_texture_ctrl)
281 {
282 knot_str_type geom_knot, color_knot, normal_knot, texture_knot;
283 GLint junk;
284 GLenum err;
285
286 *new_color_ctrl = *new_normal_ctrl = *new_texture_ctrl = NULL;
287
288 if (fill_knot_structures(nobj, &geom_knot, &color_knot, &normal_knot,
289 &texture_knot) != GLU_NO_ERROR)
290 return GLU_ERROR;
291
292 /* unify knots - all knots should have the same number of working */
293 /* ranges */
294 if (
295 (err =
296 select_knot_working_range(nobj, &geom_knot, &color_knot, &normal_knot,
297 &texture_knot)) != GLU_NO_ERROR) {
298 return err;
299 }
300 /* convert the geometry curve */
301 nobj->curve.geom.dim = get_curve_dim(nobj->curve.geom.type);
302 if ((err = convert_curve(&geom_knot, &(nobj->curve.geom), new_geom_ctrl,
303 ncontrol)) != GLU_NO_ERROR) {
304 free_unified_knots(&geom_knot, &color_knot, &normal_knot,
305 &texture_knot);
306 call_user_error(nobj, err);
307 return err;
308 }
309 /* if additional attributive curves are given convert them as well */
310 if (color_knot.unified_knot) {
311 nobj->curve.color.dim = get_curve_dim(nobj->curve.color.type);
312 if ((err = convert_curve(&color_knot, &(nobj->curve.color),
313 new_color_ctrl, &junk)) != GLU_NO_ERROR) {
314 free_unified_knots(&geom_knot, &color_knot, &normal_knot,
315 &texture_knot);
316 free(*new_geom_ctrl);
317 call_user_error(nobj, err);
318 return err;
319 }
320 }
321 if (normal_knot.unified_knot) {
322 nobj->curve.normal.dim = get_curve_dim(nobj->curve.normal.type);
323 if ((err = convert_curve(&normal_knot, &(nobj->curve.normal),
324 new_normal_ctrl, &junk)) != GLU_NO_ERROR) {
325 free_unified_knots(&geom_knot, &color_knot, &normal_knot,
326 &texture_knot);
327 free(*new_geom_ctrl);
328 if (*new_color_ctrl)
329 free(*new_color_ctrl);
330 call_user_error(nobj, err);
331 return err;
332 }
333 }
334 if (texture_knot.unified_knot) {
335 nobj->curve.texture.dim = get_curve_dim(nobj->curve.texture.type);
336 if ((err = convert_curve(&texture_knot, &(nobj->curve.texture),
337 new_texture_ctrl, &junk)) != GLU_NO_ERROR) {
338 free_unified_knots(&geom_knot, &color_knot, &normal_knot,
339 &texture_knot);
340 free(*new_geom_ctrl);
341 if (*new_color_ctrl)
342 free(*new_color_ctrl);
343 if (*new_normal_ctrl)
344 free(*new_normal_ctrl);
345 call_user_error(nobj, err);
346 return err;
347 }
348 }
349 return GLU_NO_ERROR;
350 }
351
352 /* main NURBS curve procedure */
353 void
354 do_nurbs_curve(GLUnurbsObj * nobj)
355 {
356 GLint geom_order, color_order = 0, normal_order = 0, texture_order = 0;
357 GLenum geom_type;
358 GLint n_ctrl;
359 GLfloat *new_geom_ctrl, *new_color_ctrl, *new_normal_ctrl,
360 *new_texture_ctrl;
361 GLfloat *geom_ctrl = 0, *color_ctrl = 0, *normal_ctrl = 0, *texture_ctrl = 0;
362 GLint *factors;
363 GLint i, j;
364 GLint geom_dim, color_dim = 0, normal_dim = 0, texture_dim = 0;
365
366 /* test the user supplied data */
367 if (test_nurbs_curves(nobj) != GLU_NO_ERROR)
368 return;
369
370 if (convert_curves(nobj, &new_geom_ctrl, &n_ctrl, &new_color_ctrl,
371 &new_normal_ctrl, &new_texture_ctrl) != GLU_NO_ERROR)
372 return;
373
374 geom_order = nobj->curve.geom.order;
375 geom_type = nobj->curve.geom.type;
376 geom_dim = nobj->curve.geom.dim;
377
378 if (glu_do_sampling_crv(nobj, new_geom_ctrl, n_ctrl, geom_order, geom_dim,
379 &factors) != GLU_NO_ERROR) {
380 free(new_geom_ctrl);
381 if (new_color_ctrl)
382 free(new_color_ctrl);
383 if (new_normal_ctrl)
384 free(new_normal_ctrl);
385 if (new_texture_ctrl)
386 free(new_texture_ctrl);
387 return;
388 }
389 glEnable(geom_type);
390 if (new_color_ctrl) {
391 glEnable(nobj->curve.color.type);
392 color_dim = nobj->curve.color.dim;
393 color_ctrl = new_color_ctrl;
394 color_order = nobj->curve.color.order;
395 }
396 if (new_normal_ctrl) {
397 glEnable(nobj->curve.normal.type);
398 normal_dim = nobj->curve.normal.dim;
399 normal_ctrl = new_normal_ctrl;
400 normal_order = nobj->curve.normal.order;
401 }
402 if (new_texture_ctrl) {
403 glEnable(nobj->curve.texture.type);
404 texture_dim = nobj->curve.texture.dim;
405 texture_ctrl = new_texture_ctrl;
406 texture_order = nobj->curve.texture.order;
407 }
408 for (i = 0, j = 0, geom_ctrl = new_geom_ctrl;
409 i < n_ctrl; i += geom_order, j++, geom_ctrl += geom_order * geom_dim) {
410 if (fine_culling_test_2D
411 (nobj, geom_ctrl, geom_order, geom_dim, geom_dim)) {
412 color_ctrl += color_order * color_dim;
413 normal_ctrl += normal_order * normal_dim;
414 texture_ctrl += texture_order * texture_dim;
415 continue;
416 }
417 glMap1f(geom_type, 0.0, 1.0, geom_dim, geom_order, geom_ctrl);
418 if (new_color_ctrl) {
419 glMap1f(nobj->curve.color.type, 0.0, 1.0, color_dim,
420 color_order, color_ctrl);
421 color_ctrl += color_order * color_dim;
422 }
423 if (new_normal_ctrl) {
424 glMap1f(nobj->curve.normal.type, 0.0, 1.0, normal_dim,
425 normal_order, normal_ctrl);
426 normal_ctrl += normal_order * normal_dim;
427 }
428 if (new_texture_ctrl) {
429 glMap1f(nobj->curve.texture.type, 0.0, 1.0, texture_dim,
430 texture_order, texture_ctrl);
431 texture_ctrl += texture_order * texture_dim;
432 }
433 glMapGrid1f(factors[j], 0.0, 1.0);
434 glEvalMesh1(GL_LINE, 0, factors[j]);
435 }
436 free(new_geom_ctrl);
437 free(factors);
438 if (new_color_ctrl)
439 free(new_color_ctrl);
440 if (new_normal_ctrl)
441 free(new_normal_ctrl);
442 if (new_texture_ctrl)
443 free(new_texture_ctrl);
444 }