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