1 /* $Id: tess.c,v 1.19 1999/11/04 04:07:57 gareth Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 /*****************************************************************************
29 * GLU 1.3 Polygon Tessellation by Gareth Hughes <garethh@bell-labs.com>
31 *****************************************************************************/
39 #include "tess_macros.h"
40 #include "tess_fist.h"
42 #include "tess_grid.h"
45 /*****************************************************************************
46 * Internal function prototypes:
47 *****************************************************************************/
49 static void init_callbacks( tess_callbacks_t
*callbacks
);
51 static void tess_cleanup( GLUtesselator
*tobj
);
52 static void inspect_current_contour( GLUtesselator
*tobj
);
54 void delete_contour( tess_contour_t
**contour
);
55 static void delete_all_contours( GLUtesselator
*tobj
);
57 #define TESS_CHECK_ERRORS(t) if ( (t)->error != GLU_NO_ERROR ) goto cleanup
64 /*****************************************************************************
66 * GLU TESSELLATION FUNCTIONS
68 *****************************************************************************/
71 /*****************************************************************************
73 *****************************************************************************/
74 GLUtesselator
* GLAPIENTRY
gluNewTess( void )
79 if ( getenv( "GLU_TESS_DBG_LEVEL" ) ) {
80 tess_dbg_level
= atoi( getenv( "GLU_TESS_DBG_LEVEL" ) );
82 tess_dbg_level
= DBG_LEVEL_BASE
;
86 MSG( 15, "-> gluNewTess()\n" );
88 tobj
= malloc( sizeof(GLUtesselator
) );
93 init_callbacks( &tobj
->callbacks
);
95 tobj
->boundary_only
= GL_FALSE
;
96 tobj
->winding_rule
= GLU_TESS_WINDING_ODD
;
97 tobj
->tolerance
= 0.0;
99 tobj
->plane
.normal
[X
] = 0.0;
100 tobj
->plane
.normal
[Y
] = 0.0;
101 tobj
->plane
.normal
[Z
] = 0.0;
102 tobj
->plane
.dist
= 0.0;
104 tobj
->contour_count
= 0;
105 tobj
->contours
= tobj
->last_contour
= NULL
;
106 tobj
->current_contour
= NULL
;
108 CLEAR_BBOX_2DV( tobj
->mins
, tobj
->maxs
);
110 tobj
->vertex_count
= 0;
111 tobj
->sorted_vertices
= NULL
;
115 tobj
->cvc_lists
= NULL
;
117 tobj
->edge_flag
= GL_FALSE
;
120 tobj
->error
= GLU_NO_ERROR
;
122 MSG( 15, "<- gluNewTess() tobj:%p\n", tobj
);
127 /*****************************************************************************
129 *****************************************************************************/
130 void GLAPIENTRY
gluDeleteTess( GLUtesselator
*tobj
)
132 MSG( 15, "-> gluDeleteTess( tobj:%p )\n", tobj
);
134 if ( ( tobj
->error
== GLU_NO_ERROR
) && ( tobj
->contour_count
> 0 ) )
136 /* gluEndPolygon was not called. */
137 tess_error_callback( tobj
, GLU_TESS_ERROR3
);
140 /* Delete all internal structures. */
141 tess_cleanup( tobj
);
144 MSG( 15, "<- gluDeleteTess()\n" );
148 /*****************************************************************************
149 * gluTessBeginPolygon
150 *****************************************************************************/
151 void GLAPIENTRY
gluTessBeginPolygon( GLUtesselator
*tobj
, void *polygon_data
)
153 MSG( 15, "-> gluTessBeginPolygon( tobj:%p data:%p )\n", tobj
, polygon_data
);
155 tobj
->error
= GLU_NO_ERROR
;
157 if ( tobj
->current_contour
!= NULL
)
159 /* gluEndPolygon was not called. */
160 tess_error_callback( tobj
, GLU_TESS_ERROR3
);
161 tess_cleanup( tobj
);
164 tobj
->vertex_count
= 0;
165 tobj
->data
= polygon_data
;
166 tobj
->edge_flag
= GL_FALSE
;
169 MSG( 15, "<- gluTessBeginPolygon( tobj:%p data:%p )\n", tobj
, polygon_data
);
173 /*****************************************************************************
174 * gluTessBeginContour
175 *****************************************************************************/
176 void GLAPIENTRY
gluTessBeginContour( GLUtesselator
*tobj
)
178 MSG( 15, " -> gluTessBeginContour( tobj:%p )\n", tobj
);
179 TESS_CHECK_ERRORS( tobj
);
181 if ( tobj
->current_contour
!= NULL
)
183 /* gluTessEndContour was not called. */
184 tess_error_callback( tobj
, GLU_TESS_ERROR4
);
188 tobj
->current_contour
= malloc( sizeof(tess_contour_t
) );
189 if ( tobj
->current_contour
== NULL
) {
190 tess_error_callback( tobj
, GLU_OUT_OF_MEMORY
);
194 COPY_3V( tobj
->current_contour
->plane
.normal
, tobj
->plane
.normal
);
195 tobj
->current_contour
->plane
.dist
= tobj
->plane
.dist
;
197 tobj
->current_contour
->area
= 0.0;
198 tobj
->current_contour
->orientation
= GLU_UNKNOWN
;
200 tobj
->current_contour
->label
= 0;
201 tobj
->current_contour
->winding
= 0;
203 tobj
->current_contour
->rotx
= tobj
->current_contour
->roty
= 0.0;
205 CLEAR_BBOX_2DV( tobj
->current_contour
->mins
,
206 tobj
->current_contour
->maxs
);
208 tobj
->current_contour
->vertex_count
= 0;
209 tobj
->current_contour
->vertices
=
210 tobj
->current_contour
->last_vertex
= NULL
;
212 tobj
->current_contour
->reflex_vertices
= NULL
;
213 tobj
->current_contour
->cross_vertices
= hashtable_init( HT_DEFAULT_SIZE
);
216 MSG( 15, " <- gluTessBeginContour( tobj:%p )\n", tobj
);
221 /*****************************************************************************
223 *****************************************************************************/
224 void GLAPIENTRY
gluTessVertex( GLUtesselator
*tobj
, GLdouble coords
[3],
227 tess_contour_t
*current
= tobj
->current_contour
;
228 tess_vertex_t
*last_vertex
;
230 MSG( 15, " -> gluTessVertex( tobj:%p coords:(%.2f,%.2f,%.2f) )\n", tobj
, coords
[0], coords
[1], coords
[2] );
231 TESS_CHECK_ERRORS( tobj
);
233 if ( current
== NULL
)
235 /* gluTessBeginContour was not called. */
236 tess_error_callback( tobj
, GLU_TESS_ERROR2
);
240 tobj
->vertex_count
++;
242 last_vertex
= current
->last_vertex
;
244 if ( last_vertex
== NULL
)
246 last_vertex
= malloc( sizeof(tess_vertex_t
) );
247 if ( last_vertex
== NULL
) {
248 tess_error_callback( tobj
, GLU_OUT_OF_MEMORY
);
252 current
->vertices
= last_vertex
;
253 current
->last_vertex
= last_vertex
;
255 last_vertex
->index
= -1;
256 last_vertex
->data
= vertex_data
;
258 last_vertex
->coords
[X
] = coords
[X
];
259 last_vertex
->coords
[Y
] = coords
[Y
];
260 last_vertex
->coords
[Z
] = coords
[Z
];
262 last_vertex
->side
= 0.0;
263 last_vertex
->label
= 0;
264 last_vertex
->mark
= 0;
266 last_vertex
->next
= NULL
;
267 last_vertex
->previous
= NULL
;
269 current
->vertex_count
++;
273 tess_vertex_t
*vertex
;
275 vertex
= malloc( sizeof(tess_vertex_t
) );
276 if ( vertex
== NULL
) {
277 tess_error_callback( tobj
, GLU_OUT_OF_MEMORY
);
282 vertex
->data
= vertex_data
;
284 vertex
->coords
[X
] = coords
[X
];
285 vertex
->coords
[Y
] = coords
[Y
];
286 vertex
->coords
[Z
] = coords
[Z
];
293 vertex
->previous
= last_vertex
;
295 current
->vertex_count
++;
297 last_vertex
->next
= vertex
;
298 current
->last_vertex
= vertex
;
302 MSG( 15, " <- gluTessVertex( tobj:%p )\n", tobj
);
307 /*****************************************************************************
309 *****************************************************************************/
310 void GLAPIENTRY
gluTessEndContour( GLUtesselator
*tobj
)
312 MSG( 15, " -> gluTessEndContour( tobj:%p )\n", tobj
);
313 TESS_CHECK_ERRORS( tobj
);
315 if ( tobj
->current_contour
== NULL
)
317 /* gluTessBeginContour was not called. */
318 tess_error_callback( tobj
, GLU_TESS_ERROR2
);
322 if ( tobj
->current_contour
->vertex_count
> 0 ) {
323 inspect_current_contour( tobj
);
325 delete_contour( &tobj
->current_contour
);
329 MSG( 15, " <- gluTessEndContour( tobj:%p )\n", tobj
);
334 /*****************************************************************************
336 *****************************************************************************/
337 void GLAPIENTRY
gluTessEndPolygon( GLUtesselator
*tobj
)
339 MSG( 15, "-> gluTessEndPolygon( tobj:%p )\n", tobj
);
340 TESS_CHECK_ERRORS( tobj
);
342 if ( tobj
->current_contour
!= NULL
)
344 /* gluTessBeginPolygon was not called. */
345 tess_error_callback( tobj
, GLU_TESS_ERROR1
);
348 TESS_CHECK_ERRORS( tobj
);
351 * Ensure we have at least one contour to tessellate. If we have none,
352 * clean up and exit gracefully.
354 if ( tobj
->contour_count
== 0 ) {
355 tess_cleanup( tobj
);
359 /* Wrap the contour list. */
361 tobj
->last_contour
->next
= tobj
->contours
;
362 tobj
->contours
->previous
= tobj
->last_contour
;
364 TESS_CHECK_ERRORS( tobj
);
367 * Before we tessellate the contours, ensure we have the appropriate
368 * callbacks registered. We at least need the begin, vertex and end
369 * callbacks to do any meaningful work.
371 if ( ( ( tobj
->callbacks
.begin
!= NULL
) ||
372 ( tobj
->callbacks
.beginData
!= NULL
) ) &&
373 ( ( tobj
->callbacks
.vertex
!= NULL
) ||
374 ( tobj
->callbacks
.vertexData
!= NULL
) ) &&
375 ( ( tobj
->callbacks
.end
!= NULL
) ||
376 ( tobj
->callbacks
.endData
!= NULL
) ) )
378 fist_tessellation( tobj
);
382 delete_all_contours( tobj
);
383 MSG( 15, "<- gluTessEndPolygon( tobj:%p )\n", tobj
);
387 /*****************************************************************************
389 *****************************************************************************/
390 void GLAPIENTRY
gluTessCallback( GLUtesselator
*tobj
, GLenum which
,
391 void (GLCALLBACK
*fn
)() )
395 /* Register the begin callbacks. */
397 tobj
->callbacks
.begin
= (void (GLCALLBACK
*)(GLenum
)) fn
;
399 case GLU_TESS_BEGIN_DATA
:
400 tobj
->callbacks
.beginData
= (void (GLCALLBACK
*)(GLenum
, void *)) fn
;
403 /* Register the edge flag callbacks. */
404 case GLU_TESS_EDGE_FLAG
:
405 tobj
->callbacks
.edgeFlag
= (void (GLCALLBACK
*)(GLboolean
)) fn
;
407 case GLU_TESS_EDGE_FLAG_DATA
:
408 tobj
->callbacks
.edgeFlagData
=
409 (void (GLCALLBACK
*)(GLboolean
, void *)) fn
;
412 /* Register the vertex callbacks. */
413 case GLU_TESS_VERTEX
:
414 tobj
->callbacks
.vertex
= (void (GLCALLBACK
*)(void *)) fn
;
416 case GLU_TESS_VERTEX_DATA
:
417 tobj
->callbacks
.vertexData
= (void (GLCALLBACK
*)(void *, void *)) fn
;
420 /* Register the end callbacks. */
422 tobj
->callbacks
.end
= (void (GLCALLBACK
*)(void)) fn
;
424 case GLU_TESS_END_DATA
:
425 tobj
->callbacks
.endData
= (void (GLCALLBACK
*)(void *)) fn
;
428 /* Register the error callbacks. */
430 tobj
->callbacks
.error
= (void (GLCALLBACK
*)(GLenum
)) fn
;
432 case GLU_TESS_ERROR_DATA
:
433 tobj
->callbacks
.errorData
= (void (GLCALLBACK
*)(GLenum
, void *)) fn
;
436 /* Register the combine callbacks. */
437 case GLU_TESS_COMBINE
:
438 tobj
->callbacks
.combine
=
439 (void (GLCALLBACK
*)(GLdouble
[3], void *[4],
440 GLfloat
[4], void **)) fn
;
442 case GLU_TESS_COMBINE_DATA
:
443 tobj
->callbacks
.combineData
=
444 (void (GLCALLBACK
*)(GLdouble
[3], void *[4], GLfloat
[4],
445 void **, void *)) fn
;
449 MSG( 1, " gluTessCallback( tobj:%p which:%d ) invalid enum\n", tobj
, which
);
450 tobj
->error
= GLU_INVALID_ENUM
;
456 /*****************************************************************************
459 * Set the current value of the given property.
460 *****************************************************************************/
461 void GLAPIENTRY
gluTessProperty( GLUtesselator
*tobj
, GLenum which
,
466 case GLU_TESS_BOUNDARY_ONLY
:
467 tobj
->boundary_only
= (GLboolean
) value
;
470 case GLU_TESS_TOLERANCE
:
471 MSG( 15, " gluTessProperty( tobj:%p ) tolerance: %0.9f\n", tobj
, value
);
472 tobj
->tolerance
= value
;
475 case GLU_TESS_WINDING_RULE
:
476 tobj
->winding_rule
= (GLenum
) value
;
480 MSG( 1, " gluTessProperty( tobj:%p which:%d ) invalid enum\n", tobj
, which
);
481 tobj
->error
= GLU_INVALID_ENUM
;
487 /*****************************************************************************
490 * Return the current value of the given property.
491 *****************************************************************************/
492 void GLAPIENTRY
gluGetTessProperty( GLUtesselator
*tobj
, GLenum which
,
497 case GLU_TESS_BOUNDARY_ONLY
:
498 *value
= tobj
->boundary_only
;
501 case GLU_TESS_TOLERANCE
:
502 *value
= tobj
->tolerance
;
505 case GLU_TESS_WINDING_RULE
:
506 *value
= tobj
->winding_rule
;
510 MSG( 1, " gluGetTessProperty( tobj:%p which:%d ) invalid enum\n", tobj
, which
);
511 tobj
->error
= GLU_INVALID_ENUM
;
517 /*****************************************************************************
520 * Set the current tessellation normal.
521 *****************************************************************************/
522 void GLAPIENTRY
gluTessNormal( GLUtesselator
*tobj
, GLdouble x
,
523 GLdouble y
, GLdouble z
)
525 MSG( 15, " gluTessNormal( tobj:%p n:(%.2f,%.2f,%.2f) )\n", tobj
, x
, y
, z
);
527 tobj
->plane
.normal
[X
] = x
;
528 tobj
->plane
.normal
[Y
] = y
;
529 tobj
->plane
.normal
[Z
] = z
;
534 /*****************************************************************************
536 * OBSOLETE TESSELLATION FUNCTIONS
538 *****************************************************************************/
540 void GLAPIENTRY
gluBeginPolygon( GLUtesselator
*tobj
)
542 gluTessBeginPolygon( tobj
, NULL
);
543 gluTessBeginContour( tobj
);
546 void GLAPIENTRY
gluNextContour( GLUtesselator
*tobj
, GLenum type
)
548 gluTessEndContour( tobj
);
549 gluTessBeginContour( tobj
);
552 void GLAPIENTRY
gluEndPolygon( GLUtesselator
*tobj
)
554 gluTessEndContour( tobj
);
555 gluTessEndPolygon( tobj
);
560 /*****************************************************************************
561 * tess_error_callback
563 * Internal error handler. Call the user-registered error callback.
565 * 2nd arg changed from 'errno' to 'errnum' since MSVC defines errnum as
566 * a macro (of all things) and thus breaks the build -tjump
567 *****************************************************************************/
569 void tess_error_callback( GLUtesselator
*tobj
, GLenum errnum
)
571 if ( tobj
->error
== GLU_NO_ERROR
)
573 tobj
->error
= errnum
;
576 if ( tobj
->callbacks
.errorData
!= NULL
)
578 ( tobj
->callbacks
.errorData
)( errnum
, tobj
->data
);
580 else if ( tobj
->callbacks
.error
!= NULL
)
582 ( tobj
->callbacks
.error
)( errnum
);
588 /*****************************************************************************
592 *****************************************************************************/
595 /*****************************************************************************
597 *****************************************************************************/
598 static void init_callbacks( tess_callbacks_t
*callbacks
)
600 callbacks
->begin
= ( void (GLCALLBACK
*)(GLenum
) ) NULL
;
601 callbacks
->beginData
= ( void (GLCALLBACK
*)(GLenum
, void *) ) NULL
;
602 callbacks
->edgeFlag
= ( void (GLCALLBACK
*)(GLboolean
) ) NULL
;
603 callbacks
->edgeFlagData
= ( void (GLCALLBACK
*)(GLboolean
, void *) ) NULL
;
604 callbacks
->vertex
= ( void (GLCALLBACK
*)(void *) ) NULL
;
605 callbacks
->vertexData
= ( void (GLCALLBACK
*)(void *, void *) ) NULL
;
606 callbacks
->end
= ( void (GLCALLBACK
*)(void) ) NULL
;
607 callbacks
->endData
= ( void (GLCALLBACK
*)(void *) ) NULL
;
608 callbacks
->error
= ( void (GLCALLBACK
*)(GLenum
) ) NULL
;
609 callbacks
->errorData
= ( void (GLCALLBACK
*)(GLenum
, void *) ) NULL
;
610 callbacks
->combine
= ( void (GLCALLBACK
*)(GLdouble
[3], void *[4],
611 GLfloat
[4], void **) ) NULL
;
612 callbacks
->combineData
= ( void (GLCALLBACK
*)(GLdouble
[3], void *[4],
613 GLfloat
[4], void **,
618 /*****************************************************************************
620 *****************************************************************************/
621 static void tess_cleanup( GLUtesselator
*tobj
)
623 MSG( 15, " -> tess_cleanup( tobj:%p )\n", tobj
);
625 if ( tobj
->current_contour
!= NULL
) {
626 delete_contour( &tobj
->current_contour
);
628 if ( tobj
->contours
!= NULL
) {
629 delete_all_contours( tobj
);
632 MSG( 15, " <- tess_cleanup( tobj:%p )\n", tobj
);
636 /*****************************************************************************
637 * inspect_current_contour
638 *****************************************************************************/
639 static GLenum
find_normal( GLUtesselator
*tobj
);
640 static void project_current_contour( GLUtesselator
*tobj
);
641 static GLenum
save_current_contour( GLUtesselator
*tobj
);
643 static void inspect_current_contour( GLUtesselator
*tobj
)
645 tess_contour_t
*current
= tobj
->current_contour
;
646 GLdouble origin
[3] = { 0.0, 0.0, 0.0 };
648 MSG( 15, " -> inspect_current_contour( tobj:%p )\n", tobj
);
650 if ( current
->vertex_count
< 3 )
652 MSG( 15, " count %d < 3, deleting\n", current
->vertex_count
);
653 delete_contour( &tobj
->current_contour
);
657 current
->last_vertex
->next
= current
->vertices
;
658 current
->vertices
->previous
= current
->last_vertex
;
660 if ( ( tobj
->contours
== NULL
) &&
661 ( COMPARE_3DV( current
->plane
.normal
, origin
) ) )
663 /* We haven't been given a normal, so let's take a guess. */
664 if ( find_normal( tobj
) == GLU_ERROR
) {
667 COPY_3V( tobj
->plane
.normal
, current
->plane
.normal
);
668 tobj
->plane
.dist
= current
->plane
.dist
;
672 MSG( 15, " normal: (%.2f,%.2f,%.2f)\n", tobj
->plane
.normal
[X
], tobj
->plane
.normal
[Y
], tobj
->plane
.normal
[Z
] );
675 project_current_contour( tobj
);
677 if ( save_current_contour( tobj
) == GLU_ERROR
) {
681 MSG( 15, " <- inspect_current_contour( tobj:%p )\n", tobj
);
684 /*****************************************************************************
686 *****************************************************************************/
687 static GLenum
find_normal( GLUtesselator
*tobj
)
689 tess_contour_t
*contour
= tobj
->current_contour
;
690 tess_vertex_t
*va
, *vb
, *vc
;
691 GLdouble a
[3], b
[3], c
[3];
693 MSG( 15, " -> find_normal( tobj:%p )\n", tobj
);
695 if ( contour
== NULL
) { return GLU_ERROR
; }
697 va
= contour
->vertices
;
700 /* If va and vb are the same point, keep looking for a different vertex. */
702 while ( COMPARE_3DV( va
->coords
, vb
->coords
) && ( vb
!= va
) ) {
707 /* FIXME: What error is this? */
708 tess_error_callback( tobj
, GLU_TESS_ERROR7
);
711 SUB_3V( a
, vb
->coords
, va
->coords
);
713 for ( vc
= vb
->next
; vc
!= va
; vc
= vc
->next
)
715 SUB_3V( b
, vc
->coords
, va
->coords
);
719 if ( ( ABSD( c
[X
] ) > EQUAL_EPSILON
) ||
720 ( ABSD( c
[Y
] ) > EQUAL_EPSILON
) ||
721 ( ABSD( c
[Z
] ) > EQUAL_EPSILON
) )
723 COPY_3V( contour
->plane
.normal
, c
);
724 NORMALIZE_3DV( contour
->plane
.normal
);
726 contour
->plane
.dist
= - DOT3( contour
->plane
.normal
, va
->coords
);
728 MSG( 15, " <- find_normal( tobj:%p ) n: (%.2f,%.2f,%.2f)\n", tobj
, contour
->plane
.normal
[X
], contour
->plane
.normal
[Y
], contour
->plane
.normal
[Z
] );
732 /* FIXME: What error is this? */
733 tess_error_callback( tobj
, GLU_TESS_ERROR7
);
738 /*****************************************************************************
739 * project_current_contour
740 *****************************************************************************/
741 static GLdouble
twice_contour_area( tess_vertex_t
*vertex
,
742 tess_vertex_t
*last_vertex
);
744 static void project_current_contour( GLUtesselator
*tobj
)
746 tess_contour_t
*current
= tobj
->current_contour
;
747 tess_vertex_t
*vertex
;
749 GLdouble zaxis
[3] = { 0.0, 0.0, 1.0 }, znormal
[3], xnormal
[3];
750 GLdouble dot
, rotx
, roty
;
753 MSG( 15, " -> project_current_contour( tobj:%p )\n", tobj
);
755 if ( current
== NULL
) { return; }
757 /* Rotate the plane normal around the y-axis. */
759 znormal
[X
] = current
->plane
.normal
[X
];
761 znormal
[Z
] = current
->plane
.normal
[Z
];
763 dot
= DOT3( znormal
, zaxis
);
764 current
->roty
= roty
= acos( dot
);
766 /* Rotate the plane normal around the x-axis. */
768 xnormal
[X
] = cos( roty
) * znormal
[X
] - sin( roty
) * znormal
[Z
];
769 xnormal
[Y
] = znormal
[Y
];
770 xnormal
[Z
] = sin( roty
) * znormal
[X
] + cos( roty
) * znormal
[Z
];
772 dot
= DOT3( xnormal
, zaxis
);
773 current
->rotx
= rotx
= acos( dot
);
775 for ( vertex
= current
->vertices
, i
= 0;
776 i
< current
->vertex_count
; vertex
= vertex
->next
, i
++ )
778 tess_plane_t
*plane
= ¤t
->plane
;
779 GLdouble proj
[3], yrot
[3], xrot
[3];
781 /* FIXME: This needs a cleanup, 'cos I'm sure it's inefficient. */
783 proj
[X
] = vertex
->coords
[X
] - plane
->dist
* plane
->normal
[X
];
784 proj
[Y
] = vertex
->coords
[Y
] - plane
->dist
* plane
->normal
[Y
];
785 proj
[Z
] = vertex
->coords
[Z
] - plane
->dist
* plane
->normal
[Z
];
787 yrot
[X
] = cos( roty
) * proj
[X
] - sin( roty
) * proj
[Z
];
789 yrot
[Z
] = sin( roty
) * proj
[X
] + cos( roty
) * proj
[Z
];
792 xrot
[Y
] = cos( rotx
) * yrot
[Y
] - sin( rotx
) * yrot
[Z
];
793 xrot
[Z
] = sin( rotx
) * yrot
[Y
] + cos( rotx
) * yrot
[Z
];
795 vertex
->v
[X
] = xrot
[X
];
796 vertex
->v
[Y
] = xrot
[Y
];
798 ACC_BBOX_2V( vertex
->v
, tobj
->mins
, tobj
->maxs
);
799 ACC_BBOX_2V( vertex
->v
, current
->mins
, current
->maxs
);
802 area
= twice_contour_area( current
->vertices
,
803 current
->last_vertex
);
806 current
->orientation
= GLU_CCW
;
807 current
->area
= area
;
811 current
->orientation
= GLU_CW
;
812 current
->area
= -area
;
815 MSG( 15, " <- project_current_contour( tobj:%p )\n", tobj
);
818 /*****************************************************************************
820 *****************************************************************************/
821 static GLdouble
twice_contour_area( tess_vertex_t
*vertex
,
822 tess_vertex_t
*last_vertex
)
832 vertex
= vertex
->next
;
834 while ( vertex
!= last_vertex
)
838 (vertex
->v
[X
] - x
) * (next
->v
[Y
] - y
) -
839 (vertex
->v
[Y
] - y
) * (next
->v
[X
] - x
);
841 vertex
= vertex
->next
;
847 /*****************************************************************************
848 * save_current_contour
849 *****************************************************************************/
850 static GLenum
save_current_contour( GLUtesselator
*tobj
)
852 tess_contour_t
*current
= tobj
->current_contour
;
853 tess_vertex_t
*vertex
;
856 if ( current
== NULL
) { return GLU_ERROR
; }
858 if ( tobj
->contours
== NULL
)
860 tobj
->contours
= tobj
->last_contour
= current
;
861 current
->next
= current
->previous
= NULL
;
865 current
->previous
= tobj
->last_contour
;
867 tobj
->last_contour
->next
= current
;
868 tobj
->last_contour
= current
;
870 current
->next
= NULL
;
873 for ( vertex
= current
->vertices
, i
= 0;
874 i
< current
->vertex_count
; vertex
= vertex
->next
, i
++ )
876 vertex
->shadow_vertex
= NULL
;
877 vertex
->edge_flag
= GL_TRUE
;
880 current
->type
= GLU_UNKNOWN
;
882 tobj
->contour_count
++;
883 tobj
->current_contour
= NULL
;
888 /*****************************************************************************
891 * Delete the given contour and set the pointer to NULL.
892 *****************************************************************************/
893 void delete_contour( tess_contour_t
**contour
)
895 tess_vertex_t
*vertex
, *next
;
898 if ( *contour
== NULL
) { return; }
900 vertex
= (*contour
)->vertices
;
902 for ( i
= 0 ; i
< (*contour
)->vertex_count
; i
++ )
913 /*****************************************************************************
914 * delete_all_contours
915 *****************************************************************************/
916 static void delete_all_contours( GLUtesselator
*tobj
)
918 tess_contour_t
*current
, *next_contour
;
921 if ( tobj
->current_contour
!= NULL
) {
922 delete_contour( &tobj
->current_contour
);
925 for ( current
= tobj
->contours
, i
= 0 ; i
< tobj
->contour_count
; i
++ )
927 tess_vertex_t
*vertex
= current
->vertices
, *next_vertex
;
930 for ( j
= 0 ; j
< current
->vertex_count
; j
++ )
932 next_vertex
= vertex
->next
;
934 vertex
= next_vertex
;
936 next_contour
= current
->next
;
939 current
= next_contour
;
942 tobj
->contour_count
= tobj
->vertex_count
= 0;
943 tobj
->contours
= tobj
->last_contour
= NULL
;
945 CLEAR_BBOX_2DV( tobj
->mins
, tobj
->maxs
);
947 ZERO_3V( tobj
->plane
.normal
);
948 tobj
->plane
.dist
= 0.0;
952 /*****************************************************************************
954 *****************************************************************************/
955 INLINE
void tess_msg( int level
, char *format
, ... )
959 va_start( ap
, format
);
961 if ( level
<= tess_dbg_level
) {
962 /*fprintf( DBG_STREAM, "%9.9s:%d:\t ", __FILE__, __LINE__ );*/
963 vfprintf( DBG_STREAM
, format
, ap
);
964 fflush( DBG_STREAM
);