3 * Mesa 3-D graphics library
5 * Copyright (C) 1995-2000 Brian Paul
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.
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.
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.
24 * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
25 * See README2 for more info.
40 get_curve_dim(GLenum type
)
43 case GL_MAP1_VERTEX_3
:
45 case GL_MAP1_VERTEX_4
:
53 case GL_MAP1_TEXTURE_COORD_1
:
55 case GL_MAP1_TEXTURE_COORD_2
:
57 case GL_MAP1_TEXTURE_COORD_3
:
59 case GL_MAP1_TEXTURE_COORD_4
:
62 abort(); /* TODO: is this OK? */
64 return 0; /*never get here */
68 test_nurbs_curve(GLUnurbsObj
* nobj
, curve_attribs
* attribs
)
73 if (attribs
->order
< 0) {
74 call_user_error(nobj
, GLU_INVALID_VALUE
);
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
);
82 if (attribs
->knot_count
< attribs
->order
+ 2) {
83 call_user_error(nobj
, GLU_NURBS_ERROR2
);
86 if (attribs
->stride
< 0) {
87 call_user_error(nobj
, GLU_NURBS_ERROR34
);
90 if (attribs
->knot
== NULL
|| attribs
->ctrlarray
== NULL
) {
91 call_user_error(nobj
, GLU_NURBS_ERROR36
);
94 if ((err
= test_knot(attribs
->knot_count
, attribs
->knot
, attribs
->order
))
96 call_user_error(nobj
, err
);
103 test_nurbs_curves(GLUnurbsObj
* nobj
)
105 /* test the geometric data */
106 if (test_nurbs_curve(nobj
, &(nobj
->curve
.geom
)) != GLU_NO_ERROR
)
108 /* now test the attributive data */
110 if (nobj
->curve
.color
.type
!= GLU_INVALID_ENUM
)
111 if (test_nurbs_curve(nobj
, &(nobj
->curve
.color
)) != GLU_NO_ERROR
)
114 if (nobj
->curve
.normal
.type
!= GLU_INVALID_ENUM
)
115 if (test_nurbs_curve(nobj
, &(nobj
->curve
.normal
)) != GLU_NO_ERROR
)
118 if (nobj
->curve
.texture
.type
!= GLU_INVALID_ENUM
)
119 if (test_nurbs_curve(nobj
, &(nobj
->curve
.texture
)) != GLU_NO_ERROR
)
124 /* prepare the knot information structures */
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
)
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
);
146 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
147 /* knot open at beggining */
148 geom_knot
->open_at_begin
= GL_TRUE
;
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
;
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
);
170 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
171 /* knot open at beggining */
172 color_knot
->open_at_begin
= GL_TRUE
;
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
;
181 color_knot
->open_at_end
= GL_FALSE
;
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
);
197 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
198 /* knot open at beggining */
199 normal_knot
->open_at_begin
= GL_TRUE
;
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
;
208 normal_knot
->open_at_end
= GL_FALSE
;
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
);
224 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
225 /* knot open at beggining */
226 texture_knot
->open_at_begin
= GL_TRUE
;
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
;
235 texture_knot
->open_at_end
= GL_FALSE
;
238 texture_knot
->unified_knot
= NULL
;
242 /* covert the NURBS curve into a series of adjacent Bezier curves */
244 convert_curve(knot_str_type
* the_knot
, curve_attribs
* attrib
,
245 GLfloat
** new_ctrl
, GLint
* ncontrol
)
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
;
256 if (the_knot
->unified_knot
) {
257 free(the_knot
->unified_knot
);
258 the_knot
->unified_knot
= NULL
;
260 if ((err
= calc_alphas(the_knot
)) != GLU_NO_ERROR
) {
261 free(the_knot
->new_knot
);
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
))
268 free(the_knot
->alpha
);
271 free(the_knot
->alpha
);
275 /* covert curves - geometry and possible attribute ones into equivalent */
276 /* sequence of adjacent Bezier curves */
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
)
282 knot_str_type geom_knot
, color_knot
, normal_knot
, texture_knot
;
286 *new_color_ctrl
= *new_normal_ctrl
= *new_texture_ctrl
= NULL
;
288 if (fill_knot_structures(nobj
, &geom_knot
, &color_knot
, &normal_knot
,
289 &texture_knot
) != GLU_NO_ERROR
)
292 /* unify knots - all knots should have the same number of working */
296 select_knot_working_range(nobj
, &geom_knot
, &color_knot
, &normal_knot
,
297 &texture_knot
)) != GLU_NO_ERROR
) {
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
,
306 call_user_error(nobj
, err
);
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
,
316 free(*new_geom_ctrl
);
317 call_user_error(nobj
, err
);
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
,
327 free(*new_geom_ctrl
);
329 free(*new_color_ctrl
);
330 call_user_error(nobj
, err
);
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
,
340 free(*new_geom_ctrl
);
342 free(*new_color_ctrl
);
343 if (*new_normal_ctrl
)
344 free(*new_normal_ctrl
);
345 call_user_error(nobj
, err
);
352 /* main NURBS curve procedure */
354 do_nurbs_curve(GLUnurbsObj
* nobj
)
356 GLint geom_order
, color_order
= 0, normal_order
= 0, texture_order
= 0;
359 GLfloat
*new_geom_ctrl
, *new_color_ctrl
, *new_normal_ctrl
,
361 GLfloat
*geom_ctrl
= 0, *color_ctrl
= 0, *normal_ctrl
= 0, *texture_ctrl
= 0;
364 GLint geom_dim
, color_dim
= 0, normal_dim
= 0, texture_dim
= 0;
366 /* test the user supplied data */
367 if (test_nurbs_curves(nobj
) != GLU_NO_ERROR
)
370 if (convert_curves(nobj
, &new_geom_ctrl
, &n_ctrl
, &new_color_ctrl
,
371 &new_normal_ctrl
, &new_texture_ctrl
) != GLU_NO_ERROR
)
374 geom_order
= nobj
->curve
.geom
.order
;
375 geom_type
= nobj
->curve
.geom
.type
;
376 geom_dim
= nobj
->curve
.geom
.dim
;
378 if (glu_do_sampling_crv(nobj
, new_geom_ctrl
, n_ctrl
, geom_order
, geom_dim
,
379 &factors
) != GLU_NO_ERROR
) {
382 free(new_color_ctrl
);
384 free(new_normal_ctrl
);
385 if (new_texture_ctrl
)
386 free(new_texture_ctrl
);
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
;
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
;
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
;
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
;
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
;
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
;
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
;
433 glMapGrid1f(factors
[j
], 0.0, 1.0);
434 glEvalMesh1(GL_LINE
, 0, factors
[j
]);
439 free(new_color_ctrl
);
441 free(new_normal_ctrl
);
442 if (new_texture_ctrl
)
443 free(new_texture_ctrl
);