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 call_user_error(GLUnurbsObj
* nobj
, GLenum error
)
43 if (nobj
->error_callback
!= NULL
) {
44 (*(nobj
->error_callback
)) (error
);
47 printf("NURBS error %d %s\n", error
, (char *) gluErrorString(error
));
53 GLUnurbsObj
*GLAPIENTRY
54 gluNewNurbsRenderer(void)
57 GLfloat tmp_viewport
[4];
60 n
= (GLUnurbsObj
*) malloc(sizeof(GLUnurbsObj
));
63 n
->culling
= GL_FALSE
;
64 n
->nurbs_type
= GLU_NURBS_NONE
;
65 n
->error
= GLU_NO_ERROR
;
66 n
->error_callback
= NULL
;
67 n
->auto_load_matrix
= GL_TRUE
;
68 n
->sampling_tolerance
= 50.0;
69 n
->parametric_tolerance
= 0.5;
70 n
->u_step
= n
->v_step
= 100;
71 n
->sampling_method
= GLU_PATH_LENGTH
;
72 n
->display_mode
= GLU_FILL
;
73 /* in case the user doesn't supply the sampling matrices */
74 /* set projection and modelview to identity */
75 for (i
= 0; i
< 4; i
++)
76 for (j
= 0; j
< 4; j
++)
78 n
->sampling_matrices
.model
[i
* 4 + j
] = 1.0;
79 n
->sampling_matrices
.proj
[i
* 4 + j
] = 1.0;
82 n
->sampling_matrices
.model
[i
* 4 + j
] = 0.0;
83 n
->sampling_matrices
.proj
[i
* 4 + j
] = 0.0;
85 /* and set the viewport sampling matrix to current ciewport */
86 glGetFloatv(GL_VIEWPORT
, tmp_viewport
);
87 for (i
= 0; i
< 4; i
++)
88 n
->sampling_matrices
.viewport
[i
] = tmp_viewport
[i
];
97 gluDeleteNurbsRenderer(GLUnurbsObj
* nobj
)
107 gluLoadSamplingMatrices(GLUnurbsObj
* nobj
,
108 const GLfloat modelMatrix
[16],
109 const GLfloat projMatrix
[16], const GLint viewport
[4])
113 for (i
= 0; i
< 16; i
++) {
114 nobj
->sampling_matrices
.model
[i
] = modelMatrix
[i
];
115 nobj
->sampling_matrices
.proj
[i
] = projMatrix
[i
];
117 for (i
= 0; i
< 4; i
++)
118 nobj
->sampling_matrices
.viewport
[i
] = viewport
[i
];
123 gluNurbsProperty(GLUnurbsObj
* nobj
, GLenum property
, GLfloat value
)
128 case GLU_SAMPLING_TOLERANCE
:
130 call_user_error(nobj
, GLU_INVALID_VALUE
);
133 nobj
->sampling_tolerance
= value
;
135 case GLU_PARAMETRIC_TOLERANCE
:
137 call_user_error(nobj
, GLU_INVALID_VALUE
);
140 nobj
->parametric_tolerance
= value
;
144 call_user_error(nobj
, GLU_INVALID_VALUE
);
147 nobj
->u_step
= (GLint
) value
;
151 call_user_error(nobj
, GLU_INVALID_VALUE
);
154 nobj
->v_step
= (GLint
) value
;
156 case GLU_SAMPLING_METHOD
:
157 val
= (GLenum
) value
;
158 if (val
!= GLU_PATH_LENGTH
&& val
!= GLU_PARAMETRIC_ERROR
159 && val
!= GLU_DOMAIN_DISTANCE
) {
160 call_user_error(nobj
, GLU_INVALID_ENUM
);
163 nobj
->sampling_method
= val
;
165 case GLU_DISPLAY_MODE
:
166 val
= (GLenum
) value
;
167 if (val
!= GLU_FILL
&& val
!= GLU_OUTLINE_POLYGON
168 && val
!= GLU_OUTLINE_PATCH
) {
169 call_user_error(nobj
, GLU_INVALID_ENUM
);
172 if (nobj
->nurbs_type
== GLU_NURBS_CURVE
) {
173 call_user_error(nobj
, GLU_NURBS_ERROR26
);
176 nobj
->display_mode
= val
;
177 if (val
== GLU_OUTLINE_PATCH
)
179 "NURBS, for the moment, can display only in POLYGON mode\n");
182 val
= (GLenum
) value
;
183 if (val
!= GL_TRUE
&& val
!= GL_FALSE
) {
184 call_user_error(nobj
, GLU_INVALID_ENUM
);
187 nobj
->culling
= (GLboolean
) value
;
189 case GLU_AUTO_LOAD_MATRIX
:
190 val
= (GLenum
) value
;
191 if (val
!= GL_TRUE
&& val
!= GL_FALSE
) {
192 call_user_error(nobj
, GLU_INVALID_ENUM
);
195 nobj
->auto_load_matrix
= (GLboolean
) value
;
198 call_user_error(nobj
, GLU_NURBS_ERROR26
);
204 gluGetNurbsProperty(GLUnurbsObj
* nobj
, GLenum property
, GLfloat
* value
)
207 case GLU_SAMPLING_TOLERANCE
:
208 *value
= nobj
->sampling_tolerance
;
210 case GLU_DISPLAY_MODE
:
211 *value
= (GLfloat
) (GLint
) nobj
->display_mode
;
214 *value
= nobj
->culling
? 1.0 : 0.0;
216 case GLU_AUTO_LOAD_MATRIX
:
217 *value
= nobj
->auto_load_matrix
? 1.0 : 0.0;
220 call_user_error(nobj
, GLU_INVALID_ENUM
);
227 gluBeginCurve(GLUnurbsObj
* nobj
)
229 if (nobj
->nurbs_type
== GLU_NURBS_CURVE
) {
230 call_user_error(nobj
, GLU_NURBS_ERROR6
);
233 nobj
->nurbs_type
= GLU_NURBS_CURVE
;
234 nobj
->curve
.geom
.type
= GLU_INVALID_ENUM
;
235 nobj
->curve
.color
.type
= GLU_INVALID_ENUM
;
236 nobj
->curve
.texture
.type
= GLU_INVALID_ENUM
;
237 nobj
->curve
.normal
.type
= GLU_INVALID_ENUM
;
242 gluEndCurve(GLUnurbsObj
* nobj
)
244 if (nobj
->nurbs_type
== GLU_NURBS_NONE
) {
245 call_user_error(nobj
, GLU_NURBS_ERROR7
);
248 if (nobj
->curve
.geom
.type
== GLU_INVALID_ENUM
) {
249 call_user_error(nobj
, GLU_NURBS_ERROR8
);
250 nobj
->nurbs_type
= GLU_NURBS_NONE
;
253 glPushAttrib((GLbitfield
) (GL_EVAL_BIT
| GL_ENABLE_BIT
));
254 glDisable(GL_MAP1_VERTEX_3
);
255 glDisable(GL_MAP1_VERTEX_4
);
256 glDisable(GL_MAP1_INDEX
);
257 glDisable(GL_MAP1_COLOR_4
);
258 glDisable(GL_MAP1_NORMAL
);
259 glDisable(GL_MAP1_TEXTURE_COORD_1
);
260 glDisable(GL_MAP1_TEXTURE_COORD_2
);
261 glDisable(GL_MAP1_TEXTURE_COORD_3
);
262 glDisable(GL_MAP1_TEXTURE_COORD_4
);
263 glDisable(GL_MAP2_VERTEX_3
);
264 glDisable(GL_MAP2_VERTEX_4
);
265 glDisable(GL_MAP2_INDEX
);
266 glDisable(GL_MAP2_COLOR_4
);
267 glDisable(GL_MAP2_NORMAL
);
268 glDisable(GL_MAP2_TEXTURE_COORD_1
);
269 glDisable(GL_MAP2_TEXTURE_COORD_2
);
270 glDisable(GL_MAP2_TEXTURE_COORD_3
);
271 glDisable(GL_MAP2_TEXTURE_COORD_4
);
272 do_nurbs_curve(nobj
);
274 nobj
->nurbs_type
= GLU_NURBS_NONE
;
279 gluNurbsCurve(GLUnurbsObj
* nobj
, GLint nknots
, GLfloat
* knot
,
280 GLint stride
, GLfloat
* ctlarray
, GLint order
, GLenum type
)
282 if (nobj
->nurbs_type
== GLU_NURBS_TRIM
) {
284 /* TODO: NOT IMPLEMENTED YET */
288 if (type
!= GLU_MAP1_TRIM_2
&& type
!= GLU_MAP1_TRIM_3
) {
289 call_user_error(nobj
, GLU_NURBS_ERROR14
);
292 for (ptr1
= nobj
->trim
; ptr1
->next
; ptr1
= ptr1
->next
);
293 if (ptr1
->trim_loop
) {
294 for (ptr2
= ptr1
->trim_loop
; ptr2
->next
; ptr2
= ptr2
->next
);
295 if ((ptr2
->next
= (trim_list
*) malloc(sizeof(trim_list
))) == NULL
) {
296 call_user_error(nobj
, GLU_OUT_OF_MEMORY
);
302 if ((ptr2
= (trim_list
*) malloc(sizeof(trim_list
))) == NULL
) {
303 call_user_error(nobj
, GLU_OUT_OF_MEMORY
);
306 ptr1
->trim_loop
= ptr2
;
308 ptr2
->trim_type
= GLU_TRIM_NURBS
;
309 ptr2
->curve
.nurbs_curve
.knot_count
= nknots
;
310 ptr2
->curve
.nurbs_curve
.knot
= knot
;
311 ptr2
->curve
.nurbs_curve
.stride
= stride
;
312 ptr2
->curve
.nurbs_curve
.ctrlarray
= ctlarray
;
313 ptr2
->curve
.nurbs_curve
.order
= order
;
314 ptr2
->curve
.nurbs_curve
.dim
= (type
== GLU_MAP1_TRIM_2
? 2 : 3);
315 ptr2
->curve
.nurbs_curve
.type
= type
;
320 if (type
== GLU_MAP1_TRIM_2
|| type
== GLU_MAP1_TRIM_3
) {
321 call_user_error(nobj
, GLU_NURBS_ERROR22
);
324 if (nobj
->nurbs_type
!= GLU_NURBS_CURVE
) {
325 call_user_error(nobj
, GLU_NURBS_ERROR10
);
329 case GL_MAP1_VERTEX_3
:
330 case GL_MAP1_VERTEX_4
:
331 if (nobj
->curve
.geom
.type
!= GLU_INVALID_ENUM
) {
332 call_user_error(nobj
, GLU_NURBS_ERROR8
);
335 nobj
->curve
.geom
.type
= type
;
336 nobj
->curve
.geom
.knot_count
= nknots
;
337 nobj
->curve
.geom
.knot
= knot
;
338 nobj
->curve
.geom
.stride
= stride
;
339 nobj
->curve
.geom
.ctrlarray
= ctlarray
;
340 nobj
->curve
.geom
.order
= order
;
343 case GL_MAP1_COLOR_4
:
344 nobj
->curve
.color
.type
= type
;
345 nobj
->curve
.color
.knot_count
= nknots
;
346 nobj
->curve
.color
.knot
= knot
;
347 nobj
->curve
.color
.stride
= stride
;
348 nobj
->curve
.color
.ctrlarray
= ctlarray
;
349 nobj
->curve
.color
.order
= order
;
352 nobj
->curve
.normal
.type
= type
;
353 nobj
->curve
.normal
.knot_count
= nknots
;
354 nobj
->curve
.normal
.knot
= knot
;
355 nobj
->curve
.normal
.stride
= stride
;
356 nobj
->curve
.normal
.ctrlarray
= ctlarray
;
357 nobj
->curve
.normal
.order
= order
;
359 case GL_MAP1_TEXTURE_COORD_1
:
360 case GL_MAP1_TEXTURE_COORD_2
:
361 case GL_MAP1_TEXTURE_COORD_3
:
362 case GL_MAP1_TEXTURE_COORD_4
:
363 nobj
->curve
.texture
.type
= type
;
364 nobj
->curve
.texture
.knot_count
= nknots
;
365 nobj
->curve
.texture
.knot
= knot
;
366 nobj
->curve
.texture
.stride
= stride
;
367 nobj
->curve
.texture
.ctrlarray
= ctlarray
;
368 nobj
->curve
.texture
.order
= order
;
371 call_user_error(nobj
, GLU_INVALID_ENUM
);
378 gluBeginSurface(GLUnurbsObj
* nobj
)
380 switch (nobj
->nurbs_type
) {
382 nobj
->nurbs_type
= GLU_NURBS_SURFACE
;
383 nobj
->surface
.geom
.type
= GLU_INVALID_ENUM
;
384 nobj
->surface
.color
.type
= GLU_INVALID_ENUM
;
385 nobj
->surface
.texture
.type
= GLU_INVALID_ENUM
;
386 nobj
->surface
.normal
.type
= GLU_INVALID_ENUM
;
389 call_user_error(nobj
, GLU_NURBS_ERROR16
);
391 case GLU_NURBS_SURFACE
:
392 case GLU_NURBS_NO_TRIM
:
393 case GLU_NURBS_TRIM_DONE
:
394 call_user_error(nobj
, GLU_NURBS_ERROR27
);
396 case GLU_NURBS_CURVE
:
397 call_user_error(nobj
, GLU_NURBS_ERROR6
);
404 gluEndSurface(GLUnurbsObj
* nobj
)
406 switch (nobj
->nurbs_type
) {
408 call_user_error(nobj
, GLU_NURBS_ERROR13
);
411 call_user_error(nobj
, GLU_NURBS_ERROR12
);
413 case GLU_NURBS_TRIM_DONE
:
414 /* if(nobj->trim->trim_loop==NULL)
416 call_user_error(nobj,GLU_NURBS_ERROR18);
419 /* no break - fallthrough */
420 case GLU_NURBS_NO_TRIM
:
421 glPushAttrib((GLbitfield
)
422 (GL_EVAL_BIT
| GL_ENABLE_BIT
| GL_POLYGON_BIT
));
423 glDisable(GL_MAP2_VERTEX_3
);
424 glDisable(GL_MAP2_VERTEX_4
);
425 glDisable(GL_MAP2_INDEX
);
426 glDisable(GL_MAP2_COLOR_4
);
427 glDisable(GL_MAP2_NORMAL
);
428 glDisable(GL_MAP2_TEXTURE_COORD_1
);
429 glDisable(GL_MAP2_TEXTURE_COORD_2
);
430 glDisable(GL_MAP2_TEXTURE_COORD_3
);
431 glDisable(GL_MAP2_TEXTURE_COORD_4
);
432 /* glDisable(GL_MAP1_VERTEX_3);
433 glDisable(GL_MAP1_VERTEX_4);
434 glDisable(GL_MAP1_INDEX);
435 glDisable(GL_MAP1_COLOR_4);
436 glDisable(GL_MAP1_NORMAL);
437 glDisable(GL_MAP1_TEXTURE_COORD_1);
438 glDisable(GL_MAP1_TEXTURE_COORD_2);
439 glDisable(GL_MAP1_TEXTURE_COORD_3);
440 glDisable(GL_MAP1_TEXTURE_COORD_4);*/
441 do_nurbs_surface(nobj
);
445 call_user_error(nobj
, GLU_NURBS_ERROR8
);
447 nobj
->nurbs_type
= GLU_NURBS_NONE
;
452 gluNurbsSurface(GLUnurbsObj
* nobj
,
453 GLint sknot_count
, GLfloat
* sknot
,
454 GLint tknot_count
, GLfloat
* tknot
,
455 GLint s_stride
, GLint t_stride
,
456 GLfloat
* ctrlarray
, GLint sorder
, GLint torder
, GLenum type
)
458 if (nobj
->nurbs_type
== GLU_NURBS_NO_TRIM
459 || nobj
->nurbs_type
== GLU_NURBS_TRIM
460 || nobj
->nurbs_type
== GLU_NURBS_TRIM_DONE
) {
461 if (type
== GL_MAP2_VERTEX_3
|| type
== GL_MAP2_VERTEX_4
) {
462 call_user_error(nobj
, GLU_NURBS_ERROR8
);
466 else if (nobj
->nurbs_type
!= GLU_NURBS_SURFACE
) {
467 call_user_error(nobj
, GLU_NURBS_ERROR11
);
471 case GL_MAP2_VERTEX_3
:
472 case GL_MAP2_VERTEX_4
:
473 nobj
->surface
.geom
.sknot_count
= sknot_count
;
474 nobj
->surface
.geom
.sknot
= sknot
;
475 nobj
->surface
.geom
.tknot_count
= tknot_count
;
476 nobj
->surface
.geom
.tknot
= tknot
;
477 nobj
->surface
.geom
.s_stride
= s_stride
;
478 nobj
->surface
.geom
.t_stride
= t_stride
;
479 nobj
->surface
.geom
.ctrlarray
= ctrlarray
;
480 nobj
->surface
.geom
.sorder
= sorder
;
481 nobj
->surface
.geom
.torder
= torder
;
482 nobj
->surface
.geom
.type
= type
;
483 nobj
->nurbs_type
= GLU_NURBS_NO_TRIM
;
486 case GL_MAP2_COLOR_4
:
487 nobj
->surface
.color
.sknot_count
= sknot_count
;
488 nobj
->surface
.color
.sknot
= sknot
;
489 nobj
->surface
.color
.tknot_count
= tknot_count
;
490 nobj
->surface
.color
.tknot
= tknot
;
491 nobj
->surface
.color
.s_stride
= s_stride
;
492 nobj
->surface
.color
.t_stride
= t_stride
;
493 nobj
->surface
.color
.ctrlarray
= ctrlarray
;
494 nobj
->surface
.color
.sorder
= sorder
;
495 nobj
->surface
.color
.torder
= torder
;
496 nobj
->surface
.color
.type
= type
;
499 nobj
->surface
.normal
.sknot_count
= sknot_count
;
500 nobj
->surface
.normal
.sknot
= sknot
;
501 nobj
->surface
.normal
.tknot_count
= tknot_count
;
502 nobj
->surface
.normal
.tknot
= tknot
;
503 nobj
->surface
.normal
.s_stride
= s_stride
;
504 nobj
->surface
.normal
.t_stride
= t_stride
;
505 nobj
->surface
.normal
.ctrlarray
= ctrlarray
;
506 nobj
->surface
.normal
.sorder
= sorder
;
507 nobj
->surface
.normal
.torder
= torder
;
508 nobj
->surface
.normal
.type
= type
;
510 case GL_MAP2_TEXTURE_COORD_1
:
511 case GL_MAP2_TEXTURE_COORD_2
:
512 case GL_MAP2_TEXTURE_COORD_3
:
513 case GL_MAP2_TEXTURE_COORD_4
:
514 nobj
->surface
.texture
.sknot_count
= sknot_count
;
515 nobj
->surface
.texture
.sknot
= sknot
;
516 nobj
->surface
.texture
.tknot_count
= tknot_count
;
517 nobj
->surface
.texture
.tknot
= tknot
;
518 nobj
->surface
.texture
.s_stride
= s_stride
;
519 nobj
->surface
.texture
.t_stride
= t_stride
;
520 nobj
->surface
.texture
.ctrlarray
= ctrlarray
;
521 nobj
->surface
.texture
.sorder
= sorder
;
522 nobj
->surface
.texture
.torder
= torder
;
523 nobj
->surface
.texture
.type
= type
;
526 call_user_error(nobj
, GLU_INVALID_ENUM
);
532 gluNurbsCallback(GLUnurbsObj
* nobj
, GLenum which
, void (GLCALLBACK
* fn
) ())
534 nobj
->error_callback
= (void (GLCALLBACKPCAST
) (GLenum
)) fn
;
536 if (which
!= GLU_ERROR
)
537 call_user_error(nobj
, GLU_INVALID_ENUM
);
541 gluBeginTrim(GLUnurbsObj
* nobj
)
547 if (nobj
->nurbs_type
!= GLU_NURBS_TRIM_DONE
)
548 if (nobj
->nurbs_type
!= GLU_NURBS_NO_TRIM
) {
549 call_user_error(nobj
, GLU_NURBS_ERROR15
);
552 nobj
->nurbs_type
= GLU_NURBS_TRIM
;
553 fprintf(stderr
, "NURBS - trimming not supported yet\n");
555 if ((ptr
= (nurbs_trim
*) malloc(sizeof(nurbs_trim
))) == NULL
) {
556 call_user_error(nobj
, GLU_OUT_OF_MEMORY
);
562 for (tmp_ptr
= nobj
->trim
; tmp_ptr
->next
; tmp_ptr
= tmp_ptr
->next
);
567 ptr
->trim_loop
= NULL
;
568 ptr
->segments
= NULL
;
574 gluPwlCurve(GLUnurbsObj
* nobj
, GLint count
, GLfloat
* array
, GLint stride
,
581 if (nobj
->nurbs_type
== GLU_NURBS_CURVE
) {
582 call_user_error(nobj
, GLU_NURBS_ERROR9
);
585 if (nobj
->nurbs_type
== GLU_NURBS_NONE
) {
586 call_user_error(nobj
, GLU_NURBS_ERROR19
);
589 if (type
!= GLU_MAP1_TRIM_2
&& type
!= GLU_MAP1_TRIM_3
) {
590 call_user_error(nobj
, GLU_NURBS_ERROR14
);
594 for (ptr1
= nobj
->trim
; ptr1
->next
; ptr1
= ptr1
->next
);
595 if (ptr1
->trim_loop
) {
596 for (ptr2
= ptr1
->trim_loop
; ptr2
->next
; ptr2
= ptr2
->next
);
597 if ((ptr2
->next
= (trim_list
*) malloc(sizeof(trim_list
))) == NULL
) {
598 call_user_error(nobj
, GLU_OUT_OF_MEMORY
);
604 if ((ptr2
= (trim_list
*) malloc(sizeof(trim_list
))) == NULL
) {
605 call_user_error(nobj
, GLU_OUT_OF_MEMORY
);
608 ptr1
->trim_loop
= ptr2
;
610 ptr2
->trim_type
= GLU_TRIM_PWL
;
611 ptr2
->curve
.pwl_curve
.pt_count
= count
;
612 ptr2
->curve
.pwl_curve
.ctrlarray
= array
;
613 ptr2
->curve
.pwl_curve
.stride
= stride
;
614 ptr2
->curve
.pwl_curve
.dim
= (type
== GLU_MAP1_TRIM_2
? 2 : 3);
615 ptr2
->curve
.pwl_curve
.type
= type
;
621 gluEndTrim(GLUnurbsObj
* nobj
)
623 if (nobj
->nurbs_type
!= GLU_NURBS_TRIM
) {
624 call_user_error(nobj
, GLU_NURBS_ERROR17
);
627 nobj
->nurbs_type
= GLU_NURBS_TRIM_DONE
;