1f220fa62Smrg/*
2f220fa62Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3f220fa62Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4f220fa62Smrg *
5f220fa62Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6f220fa62Smrg * copy of this software and associated documentation files (the "Software"),
7f220fa62Smrg * to deal in the Software without restriction, including without limitation
8f220fa62Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9f220fa62Smrg * and/or sell copies of the Software, and to permit persons to whom the
10f220fa62Smrg * Software is furnished to do so, subject to the following conditions:
11f220fa62Smrg *
12f220fa62Smrg * The above copyright notice including the dates of first publication and
13f220fa62Smrg * either this permission notice or a reference to
14f220fa62Smrg * http://oss.sgi.com/projects/FreeB/
15f220fa62Smrg * shall be included in all copies or substantial portions of the Software.
16f220fa62Smrg *
17f220fa62Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18f220fa62Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19f220fa62Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20f220fa62Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21f220fa62Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22f220fa62Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23f220fa62Smrg * SOFTWARE.
24f220fa62Smrg *
25f220fa62Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26f220fa62Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27f220fa62Smrg * other dealings in this Software without prior written authorization from
28f220fa62Smrg * Silicon Graphics, Inc.
29f220fa62Smrg */
30f220fa62Smrg/*
31f220fa62Smrg** Author: Eric Veach, July 1994.
32f220fa62Smrg**
33f220fa62Smrg*/
34f220fa62Smrg
35f220fa62Smrg#include "gluos.h"
36f220fa62Smrg#include <stddef.h>
37f220fa62Smrg#include <assert.h>
38f220fa62Smrg#include <setjmp.h>
39f220fa62Smrg#include "memalloc.h"
40f220fa62Smrg#include "tess.h"
41f220fa62Smrg#include "mesh.h"
42f220fa62Smrg#include "normal.h"
43f220fa62Smrg#include "sweep.h"
44f220fa62Smrg#include "tessmono.h"
45f220fa62Smrg#include "render.h"
46f220fa62Smrg
47f220fa62Smrg#define GLU_TESS_DEFAULT_TOLERANCE 0.0
48f220fa62Smrg#define GLU_TESS_MESH		100112	/* void (*)(GLUmesh *mesh)	    */
49f220fa62Smrg
50f220fa62Smrg#ifndef TRUE
51f220fa62Smrg#define TRUE 1
52f220fa62Smrg#endif
53f220fa62Smrg#ifndef FALSE
54f220fa62Smrg#define FALSE 0
55f220fa62Smrg#endif
56f220fa62Smrg
57f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
58f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
59f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
60f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
61f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
62f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
63f220fa62Smrg				    GLfloat weight[4], void **dataOut ) {}
64f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
65f220fa62Smrg
66f220fa62Smrg
67f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
68f220fa62Smrg					     void *polygonData ) {}
69f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
70f220fa62Smrg				       void *polygonData ) {}
71f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
72f220fa62Smrg					      void *polygonData ) {}
73f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
74f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
75f220fa62Smrg					     void *polygonData ) {}
76f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
77f220fa62Smrg					       void *data[4],
78f220fa62Smrg					       GLfloat weight[4],
79f220fa62Smrg					       void **outData,
80f220fa62Smrg					       void *polygonData ) {}
81f220fa62Smrg
82f220fa62Smrg/* Half-edges are allocated in pairs (see mesh.c) */
83f220fa62Smrgtypedef struct { GLUhalfEdge e, eSym; } EdgePair;
84f220fa62Smrg
85f220fa62Smrg#undef	MAX
86f220fa62Smrg#define MAX(a,b)	((a) > (b) ? (a) : (b))
87f220fa62Smrg#define MAX_FAST_ALLOC	(MAX(sizeof(EdgePair), \
88f220fa62Smrg                         MAX(sizeof(GLUvertex),sizeof(GLUface))))
89f220fa62Smrg
90f220fa62Smrg
91f220fa62SmrgGLUtesselator * GLAPIENTRY
92f220fa62SmrggluNewTess( void )
93f220fa62Smrg{
94f220fa62Smrg  GLUtesselator *tess;
95f220fa62Smrg
96f220fa62Smrg  /* Only initialize fields which can be changed by the api.  Other fields
97f220fa62Smrg   * are initialized where they are used.
98f220fa62Smrg   */
99f220fa62Smrg
100f220fa62Smrg  if (memInit( MAX_FAST_ALLOC ) == 0) {
101f220fa62Smrg     return 0;			/* out of memory */
102f220fa62Smrg  }
103f220fa62Smrg  tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
104f220fa62Smrg  if (tess == NULL) {
105f220fa62Smrg     return 0;			/* out of memory */
106f220fa62Smrg  }
107f220fa62Smrg
108f220fa62Smrg  tess->state = T_DORMANT;
109f220fa62Smrg
110f220fa62Smrg  tess->normal[0] = 0;
111f220fa62Smrg  tess->normal[1] = 0;
112f220fa62Smrg  tess->normal[2] = 0;
113f220fa62Smrg
114f220fa62Smrg  tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
115f220fa62Smrg  tess->windingRule = GLU_TESS_WINDING_ODD;
116f220fa62Smrg  tess->flagBoundary = FALSE;
117f220fa62Smrg  tess->boundaryOnly = FALSE;
118f220fa62Smrg
119f220fa62Smrg  tess->callBegin = &noBegin;
120f220fa62Smrg  tess->callEdgeFlag = &noEdgeFlag;
121f220fa62Smrg  tess->callVertex = &noVertex;
122f220fa62Smrg  tess->callEnd = &noEnd;
123f220fa62Smrg
124f220fa62Smrg  tess->callError = &noError;
125f220fa62Smrg  tess->callCombine = &noCombine;
126f220fa62Smrg  tess->callMesh = &noMesh;
127f220fa62Smrg
128f220fa62Smrg  tess->callBeginData= &__gl_noBeginData;
129f220fa62Smrg  tess->callEdgeFlagData= &__gl_noEdgeFlagData;
130f220fa62Smrg  tess->callVertexData= &__gl_noVertexData;
131f220fa62Smrg  tess->callEndData= &__gl_noEndData;
132f220fa62Smrg  tess->callErrorData= &__gl_noErrorData;
133f220fa62Smrg  tess->callCombineData= &__gl_noCombineData;
134f220fa62Smrg
135f220fa62Smrg  tess->polygonData= NULL;
136f220fa62Smrg
137f220fa62Smrg  return tess;
138f220fa62Smrg}
139f220fa62Smrg
140f220fa62Smrgstatic void MakeDormant( GLUtesselator *tess )
141f220fa62Smrg{
142f220fa62Smrg  /* Return the tessellator to its original dormant state. */
143f220fa62Smrg
144f220fa62Smrg  if( tess->mesh != NULL ) {
145f220fa62Smrg    __gl_meshDeleteMesh( tess->mesh );
146f220fa62Smrg  }
147f220fa62Smrg  tess->state = T_DORMANT;
148f220fa62Smrg  tess->lastEdge = NULL;
149f220fa62Smrg  tess->mesh = NULL;
150f220fa62Smrg}
151f220fa62Smrg
152f220fa62Smrg#define RequireState( tess, s )   if( tess->state != s ) GotoState(tess,s)
153f220fa62Smrg
154f220fa62Smrgstatic void GotoState( GLUtesselator *tess, enum TessState newState )
155f220fa62Smrg{
156f220fa62Smrg  while( tess->state != newState ) {
157f220fa62Smrg    /* We change the current state one level at a time, to get to
158f220fa62Smrg     * the desired state.
159f220fa62Smrg     */
160f220fa62Smrg    if( tess->state < newState ) {
161f220fa62Smrg      switch( tess->state ) {
162f220fa62Smrg      case T_DORMANT:
163f220fa62Smrg	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
164f220fa62Smrg	gluTessBeginPolygon( tess, NULL );
165f220fa62Smrg	break;
166f220fa62Smrg      case T_IN_POLYGON:
167f220fa62Smrg	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
168f220fa62Smrg	gluTessBeginContour( tess );
169f220fa62Smrg	break;
170f220fa62Smrg      default:
171f220fa62Smrg	 ;
172f220fa62Smrg      }
173f220fa62Smrg    } else {
174f220fa62Smrg      switch( tess->state ) {
175f220fa62Smrg      case T_IN_CONTOUR:
176f220fa62Smrg	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
177f220fa62Smrg	gluTessEndContour( tess );
178f220fa62Smrg	break;
179f220fa62Smrg      case T_IN_POLYGON:
180f220fa62Smrg	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
181f220fa62Smrg	/* gluTessEndPolygon( tess ) is too much work! */
182f220fa62Smrg	MakeDormant( tess );
183f220fa62Smrg	break;
184f220fa62Smrg      default:
185f220fa62Smrg	 ;
186f220fa62Smrg      }
187f220fa62Smrg    }
188f220fa62Smrg  }
189f220fa62Smrg}
190f220fa62Smrg
191f220fa62Smrg
192f220fa62Smrgvoid GLAPIENTRY
193f220fa62SmrggluDeleteTess( GLUtesselator *tess )
194f220fa62Smrg{
195f220fa62Smrg  RequireState( tess, T_DORMANT );
196f220fa62Smrg  memFree( tess );
197f220fa62Smrg}
198f220fa62Smrg
199f220fa62Smrg
200f220fa62Smrgvoid GLAPIENTRY
201f220fa62SmrggluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
202f220fa62Smrg{
203f220fa62Smrg  GLenum windingRule;
204f220fa62Smrg
205f220fa62Smrg  switch( which ) {
206f220fa62Smrg  case GLU_TESS_TOLERANCE:
207f220fa62Smrg    if( value < 0.0 || value > 1.0 ) break;
208f220fa62Smrg    tess->relTolerance = value;
209f220fa62Smrg    return;
210f220fa62Smrg
211f220fa62Smrg  case GLU_TESS_WINDING_RULE:
212f220fa62Smrg    windingRule = (GLenum) value;
213f220fa62Smrg    if( windingRule != value ) break;	/* not an integer */
214f220fa62Smrg
215f220fa62Smrg    switch( windingRule ) {
216f220fa62Smrg    case GLU_TESS_WINDING_ODD:
217f220fa62Smrg    case GLU_TESS_WINDING_NONZERO:
218f220fa62Smrg    case GLU_TESS_WINDING_POSITIVE:
219f220fa62Smrg    case GLU_TESS_WINDING_NEGATIVE:
220f220fa62Smrg    case GLU_TESS_WINDING_ABS_GEQ_TWO:
221f220fa62Smrg      tess->windingRule = windingRule;
222f220fa62Smrg      return;
223f220fa62Smrg    default:
224f220fa62Smrg      break;
225f220fa62Smrg    }
226f220fa62Smrg
227f220fa62Smrg  case GLU_TESS_BOUNDARY_ONLY:
228f220fa62Smrg    tess->boundaryOnly = (value != 0);
229f220fa62Smrg    return;
230f220fa62Smrg
231f220fa62Smrg  default:
232f220fa62Smrg    CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
233f220fa62Smrg    return;
234f220fa62Smrg  }
235f220fa62Smrg  CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
236f220fa62Smrg}
237f220fa62Smrg
238f220fa62Smrg/* Returns tessellator property */
239f220fa62Smrgvoid GLAPIENTRY
240f220fa62SmrggluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
241f220fa62Smrg{
242f220fa62Smrg   switch (which) {
243f220fa62Smrg   case GLU_TESS_TOLERANCE:
244f220fa62Smrg      /* tolerance should be in range [0..1] */
245f220fa62Smrg      assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
246f220fa62Smrg      *value= tess->relTolerance;
247f220fa62Smrg      break;
248f220fa62Smrg   case GLU_TESS_WINDING_RULE:
249f220fa62Smrg      assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
250f220fa62Smrg	     tess->windingRule == GLU_TESS_WINDING_NONZERO ||
251f220fa62Smrg	     tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
252f220fa62Smrg	     tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
253f220fa62Smrg	     tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
254f220fa62Smrg      *value= tess->windingRule;
255f220fa62Smrg      break;
256f220fa62Smrg   case GLU_TESS_BOUNDARY_ONLY:
257f220fa62Smrg      assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
258f220fa62Smrg      *value= tess->boundaryOnly;
259f220fa62Smrg      break;
260f220fa62Smrg   default:
261f220fa62Smrg      *value= 0.0;
262f220fa62Smrg      CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
263f220fa62Smrg      break;
264f220fa62Smrg   }
265f220fa62Smrg} /* gluGetTessProperty() */
266f220fa62Smrg
267f220fa62Smrgvoid GLAPIENTRY
268f220fa62SmrggluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
269f220fa62Smrg{
270f220fa62Smrg  tess->normal[0] = x;
271f220fa62Smrg  tess->normal[1] = y;
272f220fa62Smrg  tess->normal[2] = z;
273f220fa62Smrg}
274f220fa62Smrg
275f220fa62Smrgvoid GLAPIENTRY
276f220fa62SmrggluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
277f220fa62Smrg{
278f220fa62Smrg  switch( which ) {
279f220fa62Smrg  case GLU_TESS_BEGIN:
280f220fa62Smrg    tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
281f220fa62Smrg    return;
282f220fa62Smrg  case GLU_TESS_BEGIN_DATA:
283f220fa62Smrg    tess->callBeginData = (fn == NULL) ?
284f220fa62Smrg	&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
285f220fa62Smrg    return;
286f220fa62Smrg  case GLU_TESS_EDGE_FLAG:
287f220fa62Smrg    tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
288f220fa62Smrg					(void (GLAPIENTRY *)(GLboolean)) fn;
289f220fa62Smrg    /* If the client wants boundary edges to be flagged,
290f220fa62Smrg     * we render everything as separate triangles (no strips or fans).
291f220fa62Smrg     */
292f220fa62Smrg    tess->flagBoundary = (fn != NULL);
293f220fa62Smrg    return;
294f220fa62Smrg  case GLU_TESS_EDGE_FLAG_DATA:
295f220fa62Smrg    tess->callEdgeFlagData= (fn == NULL) ?
296f220fa62Smrg	&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
297f220fa62Smrg    /* If the client wants boundary edges to be flagged,
298f220fa62Smrg     * we render everything as separate triangles (no strips or fans).
299f220fa62Smrg     */
300f220fa62Smrg    tess->flagBoundary = (fn != NULL);
301f220fa62Smrg    return;
302f220fa62Smrg  case GLU_TESS_VERTEX:
303f220fa62Smrg    tess->callVertex = (fn == NULL) ? &noVertex :
304f220fa62Smrg				      (void (GLAPIENTRY *)(void *)) fn;
305f220fa62Smrg    return;
306f220fa62Smrg  case GLU_TESS_VERTEX_DATA:
307f220fa62Smrg    tess->callVertexData = (fn == NULL) ?
308f220fa62Smrg	&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
309f220fa62Smrg    return;
310f220fa62Smrg  case GLU_TESS_END:
311f220fa62Smrg    tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
312f220fa62Smrg    return;
313f220fa62Smrg  case GLU_TESS_END_DATA:
314f220fa62Smrg    tess->callEndData = (fn == NULL) ? &__gl_noEndData :
315f220fa62Smrg				       (void (GLAPIENTRY *)(void *)) fn;
316f220fa62Smrg    return;
317f220fa62Smrg  case GLU_TESS_ERROR:
318f220fa62Smrg    tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
319f220fa62Smrg    return;
320f220fa62Smrg  case GLU_TESS_ERROR_DATA:
321f220fa62Smrg    tess->callErrorData = (fn == NULL) ?
322f220fa62Smrg	&__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
323f220fa62Smrg    return;
324f220fa62Smrg  case GLU_TESS_COMBINE:
325f220fa62Smrg    tess->callCombine = (fn == NULL) ? &noCombine :
326f220fa62Smrg	(void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
327f220fa62Smrg    return;
328f220fa62Smrg  case GLU_TESS_COMBINE_DATA:
329f220fa62Smrg    tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
330f220fa62Smrg					   (void (GLAPIENTRY *)(GLdouble [3],
331f220fa62Smrg						     void *[4],
332f220fa62Smrg						     GLfloat [4],
333f220fa62Smrg						     void **,
334f220fa62Smrg						     void *)) fn;
335f220fa62Smrg    return;
336f220fa62Smrg  case GLU_TESS_MESH:
337f220fa62Smrg    tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
338f220fa62Smrg    return;
339f220fa62Smrg  default:
340f220fa62Smrg    CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
341f220fa62Smrg    return;
342f220fa62Smrg  }
343f220fa62Smrg}
344f220fa62Smrg
345f220fa62Smrgstatic int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
346f220fa62Smrg{
347f220fa62Smrg  GLUhalfEdge *e;
348f220fa62Smrg
349f220fa62Smrg  e = tess->lastEdge;
350f220fa62Smrg  if( e == NULL ) {
351f220fa62Smrg    /* Make a self-loop (one vertex, one edge). */
352f220fa62Smrg
353f220fa62Smrg    e = __gl_meshMakeEdge( tess->mesh );
354f220fa62Smrg    if (e == NULL) return 0;
355f220fa62Smrg    if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
356f220fa62Smrg  } else {
357f220fa62Smrg    /* Create a new vertex and edge which immediately follow e
358f220fa62Smrg     * in the ordering around the left face.
359f220fa62Smrg     */
360f220fa62Smrg    if (__gl_meshSplitEdge( e ) == NULL) return 0;
361f220fa62Smrg    e = e->Lnext;
362f220fa62Smrg  }
363f220fa62Smrg
364f220fa62Smrg  /* The new vertex is now e->Org. */
365f220fa62Smrg  e->Org->data = data;
366f220fa62Smrg  e->Org->coords[0] = coords[0];
367f220fa62Smrg  e->Org->coords[1] = coords[1];
368f220fa62Smrg  e->Org->coords[2] = coords[2];
369f220fa62Smrg
370f220fa62Smrg  /* The winding of an edge says how the winding number changes as we
371f220fa62Smrg   * cross from the edge''s right face to its left face.  We add the
372f220fa62Smrg   * vertices in such an order that a CCW contour will add +1 to
373f220fa62Smrg   * the winding number of the region inside the contour.
374f220fa62Smrg   */
375f220fa62Smrg  e->winding = 1;
376f220fa62Smrg  e->Sym->winding = -1;
377f220fa62Smrg
378f220fa62Smrg  tess->lastEdge = e;
379f220fa62Smrg
380f220fa62Smrg  return 1;
381f220fa62Smrg}
382f220fa62Smrg
383f220fa62Smrg
384f220fa62Smrgstatic void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
385f220fa62Smrg{
386f220fa62Smrg  CachedVertex *v = &tess->cache[tess->cacheCount];
387f220fa62Smrg
388f220fa62Smrg  v->data = data;
389f220fa62Smrg  v->coords[0] = coords[0];
390f220fa62Smrg  v->coords[1] = coords[1];
391f220fa62Smrg  v->coords[2] = coords[2];
392f220fa62Smrg  ++tess->cacheCount;
393f220fa62Smrg}
394f220fa62Smrg
395f220fa62Smrg
396f220fa62Smrgstatic int EmptyCache( GLUtesselator *tess )
397f220fa62Smrg{
398f220fa62Smrg  CachedVertex *v = tess->cache;
399f220fa62Smrg  CachedVertex *vLast;
400f220fa62Smrg
401f220fa62Smrg  tess->mesh = __gl_meshNewMesh();
402f220fa62Smrg  if (tess->mesh == NULL) return 0;
403f220fa62Smrg
404f220fa62Smrg  for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
405f220fa62Smrg    if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
406f220fa62Smrg  }
407f220fa62Smrg  tess->cacheCount = 0;
408f220fa62Smrg  tess->emptyCache = FALSE;
409f220fa62Smrg
410f220fa62Smrg  return 1;
411f220fa62Smrg}
412f220fa62Smrg
413f220fa62Smrg
414f220fa62Smrgvoid GLAPIENTRY
415f220fa62SmrggluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
416f220fa62Smrg{
417f220fa62Smrg  int i, tooLarge = FALSE;
418f220fa62Smrg  GLdouble x, clamped[3];
419f220fa62Smrg
420f220fa62Smrg  RequireState( tess, T_IN_CONTOUR );
421f220fa62Smrg
422f220fa62Smrg  if( tess->emptyCache ) {
423f220fa62Smrg    if ( !EmptyCache( tess ) ) {
424f220fa62Smrg       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
425f220fa62Smrg       return;
426f220fa62Smrg    }
427f220fa62Smrg    tess->lastEdge = NULL;
428f220fa62Smrg  }
429f220fa62Smrg  for( i = 0; i < 3; ++i ) {
430f220fa62Smrg    x = coords[i];
431f220fa62Smrg    if( x < - GLU_TESS_MAX_COORD ) {
432f220fa62Smrg      x = - GLU_TESS_MAX_COORD;
433f220fa62Smrg      tooLarge = TRUE;
434f220fa62Smrg    }
435f220fa62Smrg    if( x > GLU_TESS_MAX_COORD ) {
436f220fa62Smrg      x = GLU_TESS_MAX_COORD;
437f220fa62Smrg      tooLarge = TRUE;
438f220fa62Smrg    }
439f220fa62Smrg    clamped[i] = x;
440f220fa62Smrg  }
441f220fa62Smrg  if( tooLarge ) {
442f220fa62Smrg    CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
443f220fa62Smrg  }
444f220fa62Smrg
445f220fa62Smrg  if( tess->mesh == NULL ) {
446f220fa62Smrg    if( tess->cacheCount < TESS_MAX_CACHE ) {
447f220fa62Smrg      CacheVertex( tess, clamped, data );
448f220fa62Smrg      return;
449f220fa62Smrg    }
450f220fa62Smrg    if ( !EmptyCache( tess ) ) {
451f220fa62Smrg       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
452f220fa62Smrg       return;
453f220fa62Smrg    }
454f220fa62Smrg  }
455f220fa62Smrg  if ( !AddVertex( tess, clamped, data ) ) {
456f220fa62Smrg       CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
457f220fa62Smrg  }
458f220fa62Smrg}
459f220fa62Smrg
460f220fa62Smrg
461f220fa62Smrgvoid GLAPIENTRY
462f220fa62SmrggluTessBeginPolygon( GLUtesselator *tess, void *data )
463f220fa62Smrg{
464f220fa62Smrg  RequireState( tess, T_DORMANT );
465f220fa62Smrg
466f220fa62Smrg  tess->state = T_IN_POLYGON;
467f220fa62Smrg  tess->cacheCount = 0;
468f220fa62Smrg  tess->emptyCache = FALSE;
469f220fa62Smrg  tess->mesh = NULL;
470f220fa62Smrg
471f220fa62Smrg  tess->polygonData= data;
472f220fa62Smrg}
473f220fa62Smrg
474f220fa62Smrg
475f220fa62Smrgvoid GLAPIENTRY
476f220fa62SmrggluTessBeginContour( GLUtesselator *tess )
477f220fa62Smrg{
478f220fa62Smrg  RequireState( tess, T_IN_POLYGON );
479f220fa62Smrg
480f220fa62Smrg  tess->state = T_IN_CONTOUR;
481f220fa62Smrg  tess->lastEdge = NULL;
482f220fa62Smrg  if( tess->cacheCount > 0 ) {
483f220fa62Smrg    /* Just set a flag so we don't get confused by empty contours
484f220fa62Smrg     * -- these can be generated accidentally with the obsolete
485f220fa62Smrg     * NextContour() interface.
486f220fa62Smrg     */
487f220fa62Smrg    tess->emptyCache = TRUE;
488f220fa62Smrg  }
489f220fa62Smrg}
490f220fa62Smrg
491f220fa62Smrg
492f220fa62Smrgvoid GLAPIENTRY
493f220fa62SmrggluTessEndContour( GLUtesselator *tess )
494f220fa62Smrg{
495f220fa62Smrg  RequireState( tess, T_IN_CONTOUR );
496f220fa62Smrg  tess->state = T_IN_POLYGON;
497f220fa62Smrg}
498f220fa62Smrg
499f220fa62Smrgvoid GLAPIENTRY
500f220fa62SmrggluTessEndPolygon( GLUtesselator *tess )
501f220fa62Smrg{
502f220fa62Smrg  GLUmesh *mesh;
503f220fa62Smrg
504f220fa62Smrg  if (setjmp(tess->env) != 0) {
505f220fa62Smrg     /* come back here if out of memory */
506f220fa62Smrg     CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
507f220fa62Smrg     return;
508f220fa62Smrg  }
509f220fa62Smrg
510f220fa62Smrg  RequireState( tess, T_IN_POLYGON );
511f220fa62Smrg  tess->state = T_DORMANT;
512f220fa62Smrg
513f220fa62Smrg  if( tess->mesh == NULL ) {
514f220fa62Smrg    if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
515f220fa62Smrg
516f220fa62Smrg      /* Try some special code to make the easy cases go quickly
517f220fa62Smrg       * (eg. convex polygons).  This code does NOT handle multiple contours,
518f220fa62Smrg       * intersections, edge flags, and of course it does not generate
519f220fa62Smrg       * an explicit mesh either.
520f220fa62Smrg       */
521f220fa62Smrg      if( __gl_renderCache( tess )) {
522f220fa62Smrg	tess->polygonData= NULL;
523f220fa62Smrg	return;
524f220fa62Smrg      }
525f220fa62Smrg    }
526f220fa62Smrg    if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
527f220fa62Smrg  }
528f220fa62Smrg
529f220fa62Smrg  /* Determine the polygon normal and project vertices onto the plane
530f220fa62Smrg   * of the polygon.
531f220fa62Smrg   */
532f220fa62Smrg  __gl_projectPolygon( tess );
533f220fa62Smrg
534f220fa62Smrg  /* __gl_computeInterior( tess ) computes the planar arrangement specified
535f220fa62Smrg   * by the given contours, and further subdivides this arrangement
536f220fa62Smrg   * into regions.  Each region is marked "inside" if it belongs
537f220fa62Smrg   * to the polygon, according to the rule given by tess->windingRule.
538f220fa62Smrg   * Each interior region is guaranteed be monotone.
539f220fa62Smrg   */
540f220fa62Smrg  if ( !__gl_computeInterior( tess ) ) {
541f220fa62Smrg     longjmp(tess->env,1);	/* could've used a label */
542f220fa62Smrg  }
543f220fa62Smrg
544f220fa62Smrg  mesh = tess->mesh;
545f220fa62Smrg  if( ! tess->fatalError ) {
546f220fa62Smrg    int rc = 1;
547f220fa62Smrg
548f220fa62Smrg    /* If the user wants only the boundary contours, we throw away all edges
549f220fa62Smrg     * except those which separate the interior from the exterior.
550f220fa62Smrg     * Otherwise we tessellate all the regions marked "inside".
551f220fa62Smrg     */
552f220fa62Smrg    if( tess->boundaryOnly ) {
553f220fa62Smrg      rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
554f220fa62Smrg    } else {
555f220fa62Smrg      rc = __gl_meshTessellateInterior( mesh );
556f220fa62Smrg    }
557f220fa62Smrg    if (rc == 0) longjmp(tess->env,1);	/* could've used a label */
558f220fa62Smrg
559f220fa62Smrg    __gl_meshCheckMesh( mesh );
560f220fa62Smrg
561f220fa62Smrg    if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
562f220fa62Smrg       || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
563f220fa62Smrg       || tess->callBeginData != &__gl_noBeginData
564f220fa62Smrg       || tess->callEndData != &__gl_noEndData
565f220fa62Smrg       || tess->callVertexData != &__gl_noVertexData
566f220fa62Smrg       || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
567f220fa62Smrg    {
568f220fa62Smrg      if( tess->boundaryOnly ) {
569f220fa62Smrg	__gl_renderBoundary( tess, mesh );  /* output boundary contours */
570f220fa62Smrg      } else {
571f220fa62Smrg	__gl_renderMesh( tess, mesh );	   /* output strips and fans */
572f220fa62Smrg      }
573f220fa62Smrg    }
574f220fa62Smrg    if( tess->callMesh != &noMesh ) {
575f220fa62Smrg
576f220fa62Smrg      /* Throw away the exterior faces, so that all faces are interior.
577f220fa62Smrg       * This way the user doesn't have to check the "inside" flag,
578f220fa62Smrg       * and we don't need to even reveal its existence.  It also leaves
579f220fa62Smrg       * the freedom for an implementation to not generate the exterior
580f220fa62Smrg       * faces in the first place.
581f220fa62Smrg       */
582f220fa62Smrg      __gl_meshDiscardExterior( mesh );
583f220fa62Smrg      (*tess->callMesh)( mesh );		/* user wants the mesh itself */
584f220fa62Smrg      tess->mesh = NULL;
585f220fa62Smrg      tess->polygonData= NULL;
586f220fa62Smrg      return;
587f220fa62Smrg    }
588f220fa62Smrg  }
589f220fa62Smrg  __gl_meshDeleteMesh( mesh );
590f220fa62Smrg  tess->polygonData= NULL;
591f220fa62Smrg  tess->mesh = NULL;
592f220fa62Smrg}
593f220fa62Smrg
594f220fa62Smrg
595f220fa62Smrg/*XXXblythe unused function*/
596f220fa62Smrg#if 0
597f220fa62Smrgvoid GLAPIENTRY
598f220fa62SmrggluDeleteMesh( GLUmesh *mesh )
599f220fa62Smrg{
600f220fa62Smrg  __gl_meshDeleteMesh( mesh );
601f220fa62Smrg}
602f220fa62Smrg#endif
603f220fa62Smrg
604f220fa62Smrg
605f220fa62Smrg
606f220fa62Smrg/*******************************************************/
607f220fa62Smrg
608f220fa62Smrg/* Obsolete calls -- for backward compatibility */
609f220fa62Smrg
610f220fa62Smrgvoid GLAPIENTRY
611f220fa62SmrggluBeginPolygon( GLUtesselator *tess )
612f220fa62Smrg{
613f220fa62Smrg  gluTessBeginPolygon( tess, NULL );
614f220fa62Smrg  gluTessBeginContour( tess );
615f220fa62Smrg}
616f220fa62Smrg
617f220fa62Smrg
618f220fa62Smrg/*ARGSUSED*/
619f220fa62Smrgvoid GLAPIENTRY
620f220fa62SmrggluNextContour( GLUtesselator *tess, GLenum type )
621f220fa62Smrg{
622f220fa62Smrg  gluTessEndContour( tess );
623f220fa62Smrg  gluTessBeginContour( tess );
624f220fa62Smrg}
625f220fa62Smrg
626f220fa62Smrg
627f220fa62Smrgvoid GLAPIENTRY
628f220fa62SmrggluEndPolygon( GLUtesselator *tess )
629f220fa62Smrg{
630f220fa62Smrg  gluTessEndContour( tess );
631f220fa62Smrg  gluTessEndPolygon( tess );
632f220fa62Smrg}
633