1 /* $Id: nurbscrv.c,v 1.2 2000/07/11 14:11:04 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-2000 Brian Paul
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.
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.
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.
25 * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
26 * See README2 for more info.
41 get_curve_dim(GLenum type
)
44 case GL_MAP1_VERTEX_3
:
46 case GL_MAP1_VERTEX_4
:
54 case GL_MAP1_TEXTURE_COORD_1
:
56 case GL_MAP1_TEXTURE_COORD_2
:
58 case GL_MAP1_TEXTURE_COORD_3
:
60 case GL_MAP1_TEXTURE_COORD_4
:
63 abort(); /* TODO: is this OK? */
65 return 0; /*never get here */
69 test_nurbs_curve(GLUnurbsObj
* nobj
, curve_attribs
* attribs
)
74 if (attribs
->order
< 0) {
75 call_user_error(nobj
, GLU_INVALID_VALUE
);
78 glGetIntegerv(GL_MAX_EVAL_ORDER
, &tmp_int
);
79 if (attribs
->order
> tmp_int
|| attribs
->order
< 2) {
80 call_user_error(nobj
, GLU_NURBS_ERROR1
);
83 if (attribs
->knot_count
< attribs
->order
+ 2) {
84 call_user_error(nobj
, GLU_NURBS_ERROR2
);
87 if (attribs
->stride
< 0) {
88 call_user_error(nobj
, GLU_NURBS_ERROR34
);
91 if (attribs
->knot
== NULL
|| attribs
->ctrlarray
== NULL
) {
92 call_user_error(nobj
, GLU_NURBS_ERROR36
);
95 if ((err
= test_knot(attribs
->knot_count
, attribs
->knot
, attribs
->order
))
97 call_user_error(nobj
, err
);
104 test_nurbs_curves(GLUnurbsObj
* nobj
)
106 /* test the geometric data */
107 if (test_nurbs_curve(nobj
, &(nobj
->curve
.geom
)) != GLU_NO_ERROR
)
109 /* now test the attributive data */
111 if (nobj
->curve
.color
.type
!= GLU_INVALID_ENUM
)
112 if (test_nurbs_curve(nobj
, &(nobj
->curve
.color
)) != GLU_NO_ERROR
)
115 if (nobj
->curve
.normal
.type
!= GLU_INVALID_ENUM
)
116 if (test_nurbs_curve(nobj
, &(nobj
->curve
.normal
)) != GLU_NO_ERROR
)
119 if (nobj
->curve
.texture
.type
!= GLU_INVALID_ENUM
)
120 if (test_nurbs_curve(nobj
, &(nobj
->curve
.texture
)) != GLU_NO_ERROR
)
125 /* prepare the knot information structures */
127 fill_knot_structures(GLUnurbsObj
* nobj
, knot_str_type
* geom_knot
,
128 knot_str_type
* color_knot
, knot_str_type
* normal_knot
,
129 knot_str_type
* texture_knot
)
136 geom_knot
->unified_knot
= NULL
;
137 knot
= geom_knot
->knot
= nobj
->curve
.geom
.knot
;
138 nknots
= geom_knot
->nknots
= nobj
->curve
.geom
.knot_count
;
139 order
= geom_knot
->order
= nobj
->curve
.geom
.order
;
140 geom_knot
->delta_nknots
= 0;
141 t_min
= geom_knot
->t_min
= order
- 1;
142 t_max
= geom_knot
->t_max
= nknots
- order
;
143 if (fabs(knot
[t_min
] - knot
[t_max
]) < EPSILON
) {
144 call_user_error(nobj
, GLU_NURBS_ERROR3
);
147 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
148 /* knot open at beggining */
149 geom_knot
->open_at_begin
= GL_TRUE
;
152 geom_knot
->open_at_begin
= GL_FALSE
;
153 if (fabs(knot
[t_max
] - knot
[nknots
- 1]) < EPSILON
) {
154 /* knot open at end */
155 geom_knot
->open_at_end
= GL_TRUE
;
158 geom_knot
->open_at_end
= GL_FALSE
;
159 if (nobj
->curve
.color
.type
!= GLU_INVALID_ENUM
) {
160 color_knot
->unified_knot
= (GLfloat
*) 1;
161 knot
= color_knot
->knot
= nobj
->curve
.color
.knot
;
162 nknots
= color_knot
->nknots
= nobj
->curve
.color
.knot_count
;
163 order
= color_knot
->order
= nobj
->curve
.color
.order
;
164 color_knot
->delta_nknots
= 0;
165 t_min
= color_knot
->t_min
= order
- 1;
166 t_max
= color_knot
->t_max
= nknots
- order
;
167 if (fabs(knot
[t_min
] - knot
[t_max
]) < EPSILON
) {
168 call_user_error(nobj
, GLU_NURBS_ERROR3
);
171 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
172 /* knot open at beggining */
173 color_knot
->open_at_begin
= GL_TRUE
;
176 color_knot
->open_at_begin
= GL_FALSE
;
177 if (fabs(knot
[t_max
] - knot
[nknots
- 1]) < EPSILON
) {
178 /* knot open at end */
179 color_knot
->open_at_end
= GL_TRUE
;
182 color_knot
->open_at_end
= GL_FALSE
;
185 color_knot
->unified_knot
= NULL
;
186 if (nobj
->curve
.normal
.type
!= GLU_INVALID_ENUM
) {
187 normal_knot
->unified_knot
= (GLfloat
*) 1;
188 knot
= normal_knot
->knot
= nobj
->curve
.normal
.knot
;
189 nknots
= normal_knot
->nknots
= nobj
->curve
.normal
.knot_count
;
190 order
= normal_knot
->order
= nobj
->curve
.normal
.order
;
191 normal_knot
->delta_nknots
= 0;
192 t_min
= normal_knot
->t_min
= order
- 1;
193 t_max
= normal_knot
->t_max
= nknots
- order
;
194 if (fabs(knot
[t_min
] - knot
[t_max
]) < EPSILON
) {
195 call_user_error(nobj
, GLU_NURBS_ERROR3
);
198 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
199 /* knot open at beggining */
200 normal_knot
->open_at_begin
= GL_TRUE
;
203 normal_knot
->open_at_begin
= GL_FALSE
;
204 if (fabs(knot
[t_max
] - knot
[nknots
- 1]) < EPSILON
) {
205 /* knot open at end */
206 normal_knot
->open_at_end
= GL_TRUE
;
209 normal_knot
->open_at_end
= GL_FALSE
;
212 normal_knot
->unified_knot
= NULL
;
213 if (nobj
->curve
.texture
.type
!= GLU_INVALID_ENUM
) {
214 texture_knot
->unified_knot
= (GLfloat
*) 1;
215 knot
= texture_knot
->knot
= nobj
->curve
.texture
.knot
;
216 nknots
= texture_knot
->nknots
= nobj
->curve
.texture
.knot_count
;
217 order
= texture_knot
->order
= nobj
->curve
.texture
.order
;
218 texture_knot
->delta_nknots
= 0;
219 t_min
= texture_knot
->t_min
= order
- 1;
220 t_max
= texture_knot
->t_max
= nknots
- order
;
221 if (fabs(knot
[t_min
] - knot
[t_max
]) < EPSILON
) {
222 call_user_error(nobj
, GLU_NURBS_ERROR3
);
225 if (fabs(knot
[0] - knot
[t_min
]) < EPSILON
) {
226 /* knot open at beggining */
227 texture_knot
->open_at_begin
= GL_TRUE
;
230 texture_knot
->open_at_begin
= GL_FALSE
;
231 if (fabs(knot
[t_max
] - knot
[nknots
- 1]) < EPSILON
) {
232 /* knot open at end */
233 texture_knot
->open_at_end
= GL_TRUE
;
236 texture_knot
->open_at_end
= GL_FALSE
;
239 texture_knot
->unified_knot
= NULL
;
243 /* covert the NURBS curve into a series of adjacent Bezier curves */
245 convert_curve(knot_str_type
* the_knot
, curve_attribs
* attrib
,
246 GLfloat
** new_ctrl
, GLint
* ncontrol
)
250 if ((err
= explode_knot(the_knot
)) != GLU_NO_ERROR
) {
251 if (the_knot
->unified_knot
) {
252 free(the_knot
->unified_knot
);
253 the_knot
->unified_knot
= NULL
;
257 if (the_knot
->unified_knot
) {
258 free(the_knot
->unified_knot
);
259 the_knot
->unified_knot
= NULL
;
261 if ((err
= calc_alphas(the_knot
)) != GLU_NO_ERROR
) {
262 free(the_knot
->new_knot
);
265 free(the_knot
->new_knot
);
266 if ((err
= calc_new_ctrl_pts(attrib
->ctrlarray
, attrib
->stride
, the_knot
,
267 attrib
->dim
, new_ctrl
, ncontrol
))
269 free(the_knot
->alpha
);
272 free(the_knot
->alpha
);
276 /* covert curves - geometry and possible attribute ones into equivalent */
277 /* sequence of adjacent Bezier curves */
279 convert_curves(GLUnurbsObj
* nobj
, GLfloat
** new_geom_ctrl
,
280 GLint
* ncontrol
, GLfloat
** new_color_ctrl
,
281 GLfloat
** new_normal_ctrl
, GLfloat
** new_texture_ctrl
)
283 knot_str_type geom_knot
, color_knot
, normal_knot
, texture_knot
;
287 *new_color_ctrl
= *new_normal_ctrl
= *new_texture_ctrl
= NULL
;
289 if (fill_knot_structures(nobj
, &geom_knot
, &color_knot
, &normal_knot
,
290 &texture_knot
) != GLU_NO_ERROR
)
293 /* unify knots - all knots should have the same number of working */
297 select_knot_working_range(nobj
, &geom_knot
, &color_knot
, &normal_knot
,
298 &texture_knot
)) != GLU_NO_ERROR
) {
301 /* convert the geometry curve */
302 nobj
->curve
.geom
.dim
= get_curve_dim(nobj
->curve
.geom
.type
);
303 if ((err
= convert_curve(&geom_knot
, &(nobj
->curve
.geom
), new_geom_ctrl
,
304 ncontrol
)) != GLU_NO_ERROR
) {
305 free_unified_knots(&geom_knot
, &color_knot
, &normal_knot
,
307 call_user_error(nobj
, err
);
310 /* if additional attributive curves are given convert them as well */
311 if (color_knot
.unified_knot
) {
312 nobj
->curve
.color
.dim
= get_curve_dim(nobj
->curve
.color
.type
);
313 if ((err
= convert_curve(&color_knot
, &(nobj
->curve
.color
),
314 new_color_ctrl
, &junk
)) != GLU_NO_ERROR
) {
315 free_unified_knots(&geom_knot
, &color_knot
, &normal_knot
,
317 free(*new_geom_ctrl
);
318 call_user_error(nobj
, err
);
322 if (normal_knot
.unified_knot
) {
323 nobj
->curve
.normal
.dim
= get_curve_dim(nobj
->curve
.normal
.type
);
324 if ((err
= convert_curve(&normal_knot
, &(nobj
->curve
.normal
),
325 new_normal_ctrl
, &junk
)) != GLU_NO_ERROR
) {
326 free_unified_knots(&geom_knot
, &color_knot
, &normal_knot
,
328 free(*new_geom_ctrl
);
330 free(*new_color_ctrl
);
331 call_user_error(nobj
, err
);
335 if (texture_knot
.unified_knot
) {
336 nobj
->curve
.texture
.dim
= get_curve_dim(nobj
->curve
.texture
.type
);
337 if ((err
= convert_curve(&texture_knot
, &(nobj
->curve
.texture
),
338 new_texture_ctrl
, &junk
)) != GLU_NO_ERROR
) {
339 free_unified_knots(&geom_knot
, &color_knot
, &normal_knot
,
341 free(*new_geom_ctrl
);
343 free(*new_color_ctrl
);
344 if (*new_normal_ctrl
)
345 free(*new_normal_ctrl
);
346 call_user_error(nobj
, err
);
353 /* main NURBS curve procedure */
355 do_nurbs_curve(GLUnurbsObj
* nobj
)
357 GLint geom_order
, color_order
= 0, normal_order
= 0, texture_order
= 0;
360 GLfloat
*new_geom_ctrl
, *new_color_ctrl
, *new_normal_ctrl
,
362 GLfloat
*geom_ctrl
, *color_ctrl
, *normal_ctrl
, *texture_ctrl
;
365 GLint geom_dim
, color_dim
= 0, normal_dim
= 0, texture_dim
= 0;
367 /* test the user supplied data */
368 if (test_nurbs_curves(nobj
) != GLU_NO_ERROR
)
371 if (convert_curves(nobj
, &new_geom_ctrl
, &n_ctrl
, &new_color_ctrl
,
372 &new_normal_ctrl
, &new_texture_ctrl
) != GLU_NO_ERROR
)
375 geom_order
= nobj
->curve
.geom
.order
;
376 geom_type
= nobj
->curve
.geom
.type
;
377 geom_dim
= nobj
->curve
.geom
.dim
;
379 if (glu_do_sampling_crv(nobj
, new_geom_ctrl
, n_ctrl
, geom_order
, geom_dim
,
380 &factors
) != GLU_NO_ERROR
) {
383 free(new_color_ctrl
);
385 free(new_normal_ctrl
);
386 if (new_texture_ctrl
)
387 free(new_texture_ctrl
);
391 if (new_color_ctrl
) {
392 glEnable(nobj
->curve
.color
.type
);
393 color_dim
= nobj
->curve
.color
.dim
;
394 color_ctrl
= new_color_ctrl
;
395 color_order
= nobj
->curve
.color
.order
;
397 if (new_normal_ctrl
) {
398 glEnable(nobj
->curve
.normal
.type
);
399 normal_dim
= nobj
->curve
.normal
.dim
;
400 normal_ctrl
= new_normal_ctrl
;
401 normal_order
= nobj
->curve
.normal
.order
;
403 if (new_texture_ctrl
) {
404 glEnable(nobj
->curve
.texture
.type
);
405 texture_dim
= nobj
->curve
.texture
.dim
;
406 texture_ctrl
= new_texture_ctrl
;
407 texture_order
= nobj
->curve
.texture
.order
;
409 for (i
= 0, j
= 0, geom_ctrl
= new_geom_ctrl
;
410 i
< n_ctrl
; i
+= geom_order
, j
++, geom_ctrl
+= geom_order
* geom_dim
) {
411 if (fine_culling_test_2D
412 (nobj
, geom_ctrl
, geom_order
, geom_dim
, geom_dim
)) {
413 color_ctrl
+= color_order
* color_dim
;
414 normal_ctrl
+= normal_order
* normal_dim
;
415 texture_ctrl
+= texture_order
* texture_dim
;
418 glMap1f(geom_type
, 0.0, 1.0, geom_dim
, geom_order
, geom_ctrl
);
419 if (new_color_ctrl
) {
420 glMap1f(nobj
->curve
.color
.type
, 0.0, 1.0, color_dim
,
421 color_order
, color_ctrl
);
422 color_ctrl
+= color_order
* color_dim
;
424 if (new_normal_ctrl
) {
425 glMap1f(nobj
->curve
.normal
.type
, 0.0, 1.0, normal_dim
,
426 normal_order
, normal_ctrl
);
427 normal_ctrl
+= normal_order
* normal_dim
;
429 if (new_texture_ctrl
) {
430 glMap1f(nobj
->curve
.texture
.type
, 0.0, 1.0, texture_dim
,
431 texture_order
, texture_ctrl
);
432 texture_ctrl
+= texture_order
* texture_dim
;
434 glMapGrid1f(factors
[j
], 0.0, 1.0);
435 glEvalMesh1(GL_LINE
, 0, factors
[j
]);
440 free(new_color_ctrl
);
442 free(new_normal_ctrl
);
443 if (new_texture_ctrl
)
444 free(new_texture_ctrl
);