1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34 * Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
35 * All rights reserved.
36 */
37 
38 /*
39 ** License Applicability. Except to the extent portions of this file are
40 ** made subject to an alternative license as permitted in the SGI Free
41 ** Software License B, Version 1.1 (the "License"), the contents of this
42 ** file are subject only to the provisions of the License. You may not use
43 ** this file except in compliance with the License. You may obtain a copy
44 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
45 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
46 **
47 ** http://oss.sgi.com/projects/FreeB
48 **
49 ** Note that, as provided in the License, the Software is distributed on an
50 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
51 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
52 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
53 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
54 **
55 ** NOTE:  The Original Code (as defined below) has been licensed to Sun
56 ** Microsystems, Inc. ("Sun") under the SGI Free Software License B
57 ** (Version 1.1), shown above ("SGI License").   Pursuant to Section
58 ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
59 ** you under an alternative license ("Alternative License").  This
60 ** Alternative License includes all of the provisions of the SGI License
61 ** except that Section 2.2 and 11 are omitted.  Any differences between
62 ** the Alternative License and the SGI License are offered solely by Sun
63 ** and not by SGI.
64 **
65 ** Original Code. The Original Code is: OpenGL Sample Implementation,
66 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
67 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
68 ** Copyright in any portions created by third parties is as indicated
69 ** elsewhere herein. All Rights Reserved.
70 **
71 ** Additional Notice Provisions: The application programming interfaces
72 ** established by SGI in conjunction with the Original Code are The
73 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
74 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
75 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
76 ** Window System(R) (Version 1.3), released October 19, 1998. This software
77 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
78 ** published by SGI, but has not been independently verified as being
79 ** compliant with the OpenGL(R) version 1.2.1 Specification.
80 **
81 ** Author: Eric Veach, July 1994
82 ** Java Port: Pepijn Van Eeckhoudt, July 2003
83 ** Java Port: Nathan Parker Burg, August 2003
84 */
85 package org.lwjgl.util.glu.tessellation;
86 
87 import org.lwjgl.util.glu.GLUtessellator;
88 import org.lwjgl.util.glu.GLUtessellatorCallback;
89 import org.lwjgl.util.glu.GLUtessellatorCallbackAdapter;
90 
91 import static org.lwjgl.util.glu.GLU.*;
92 
93 public class GLUtessellatorImpl implements GLUtessellator {
94     public static final int TESS_MAX_CACHE = 100;
95 
96     private int state;		/* what begin/end calls have we seen? */
97 
98     private GLUhalfEdge lastEdge;	/* lastEdge->Org is the most recent vertex */
99     GLUmesh mesh;		/* stores the input contours, and eventually
100                                    the tessellation itself */
101 
102     /*** state needed for projecting onto the sweep plane ***/
103 
104     double[] normal = new double[3];	/* user-specified normal (if provided) */
105     double[] sUnit = new double[3];	/* unit vector in s-direction (debugging) */
106     double[] tUnit = new double[3];	/* unit vector in t-direction (debugging) */
107 
108     /*** state needed for the line sweep ***/
109 
110     private double relTolerance;	/* tolerance for merging features */
111     int windingRule;	/* rule for determining polygon interior */
112     boolean fatalError;	/* fatal error: needed combine callback */
113 
114     Dict dict;		/* edge dictionary for sweep line */
115     PriorityQ pq;		/* priority queue of vertex events */
116     GLUvertex event;		/* current sweep event being processed */
117 
118     /*** state needed for rendering callbacks (see render.c) ***/
119 
120     boolean flagBoundary;	/* mark boundary edges (use EdgeFlag) */
121     boolean boundaryOnly;	/* Extract contours, not triangles */
122     GLUface lonelyTriList;
123     /* list of triangles which could not be rendered as strips or fans */
124 
125 
126 
127     /*** state needed to cache single-contour polygons for renderCache() */
128 
129     private boolean flushCacheOnNextVertex;		/* empty cache on next vertex() call */
130     int cacheCount;		/* number of cached vertices */
131     CachedVertex[] cache = new CachedVertex[TESS_MAX_CACHE];	/* the vertex data */
132 
133     /*** rendering callbacks that also pass polygon data  ***/
134     private Object polygonData;		/* client data for current polygon */
135 
136     private GLUtessellatorCallback callBegin;
137     private GLUtessellatorCallback callEdgeFlag;
138     private GLUtessellatorCallback callVertex;
139     private GLUtessellatorCallback callEnd;
140 //    private GLUtessellatorCallback callMesh;
141     private GLUtessellatorCallback callError;
142     private GLUtessellatorCallback callCombine;
143 
144     private GLUtessellatorCallback callBeginData;
145     private GLUtessellatorCallback callEdgeFlagData;
146     private GLUtessellatorCallback callVertexData;
147     private GLUtessellatorCallback callEndData;
148 //    private GLUtessellatorCallback callMeshData;
149     private GLUtessellatorCallback callErrorData;
150     private GLUtessellatorCallback callCombineData;
151 
152     private static final double GLU_TESS_DEFAULT_TOLERANCE = 0.0;
153 //    private static final int GLU_TESS_MESH = 100112;	/* void (*)(GLUmesh *mesh)	    */
154     private static GLUtessellatorCallback NULL_CB = new GLUtessellatorCallbackAdapter();
155 
156 //    #define MAX_FAST_ALLOC	(MAX(sizeof(EdgePair), \
157 //                 MAX(sizeof(GLUvertex),sizeof(GLUface))))
158 
GLUtessellatorImpl()159     public GLUtessellatorImpl() {
160         state = TessState.T_DORMANT;
161 
162         normal[0] = 0;
163         normal[1] = 0;
164         normal[2] = 0;
165 
166         relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
167         windingRule = GLU_TESS_WINDING_ODD;
168         flagBoundary = false;
169         boundaryOnly = false;
170 
171         callBegin = NULL_CB;
172         callEdgeFlag = NULL_CB;
173         callVertex = NULL_CB;
174         callEnd = NULL_CB;
175         callError = NULL_CB;
176         callCombine = NULL_CB;
177 //        callMesh = NULL_CB;
178 
179         callBeginData = NULL_CB;
180         callEdgeFlagData = NULL_CB;
181         callVertexData = NULL_CB;
182         callEndData = NULL_CB;
183         callErrorData = NULL_CB;
184         callCombineData = NULL_CB;
185 
186         polygonData = null;
187 
188         for (int i = 0; i < cache.length; i++) {
189             cache[i] = new CachedVertex();
190         }
191     }
192 
gluNewTess()193     public static GLUtessellator gluNewTess()
194     {
195         return new GLUtessellatorImpl();
196     }
197 
198 
makeDormant()199     private void makeDormant() {
200         /* Return the tessellator to its original dormant state. */
201 
202         if (mesh != null) {
203             Mesh.__gl_meshDeleteMesh(mesh);
204         }
205         state = TessState.T_DORMANT;
206         lastEdge = null;
207         mesh = null;
208     }
209 
requireState(int newState)210     private void requireState(int newState) {
211         if (state != newState) gotoState(newState);
212     }
213 
gotoState(int newState)214     private void gotoState(int newState) {
215         while (state != newState) {
216             /* We change the current state one level at a time, to get to
217              * the desired state.
218              */
219             if (state < newState) {
220                 if (state == TessState.T_DORMANT) {
221                     callErrorOrErrorData(GLU_TESS_MISSING_BEGIN_POLYGON);
222                     gluTessBeginPolygon(null);
223                 } else if (state == TessState.T_IN_POLYGON) {
224                     callErrorOrErrorData(GLU_TESS_MISSING_BEGIN_CONTOUR);
225                     gluTessBeginContour();
226                 }
227             } else {
228                 if (state == TessState.T_IN_CONTOUR) {
229                     callErrorOrErrorData(GLU_TESS_MISSING_END_CONTOUR);
230                     gluTessEndContour();
231                 } else if (state == TessState.T_IN_POLYGON) {
232                     callErrorOrErrorData(GLU_TESS_MISSING_END_POLYGON);
233                     /* gluTessEndPolygon( tess ) is too much work! */
234                     makeDormant();
235                 }
236             }
237         }
238     }
239 
gluDeleteTess()240     public void gluDeleteTess() {
241         requireState(TessState.T_DORMANT);
242     }
243 
gluTessProperty(int which, double value)244     public void gluTessProperty(int which, double value) {
245         switch (which) {
246             case GLU_TESS_TOLERANCE:
247                 if (value < 0.0 || value > 1.0) break;
248                 relTolerance = value;
249                 return;
250 
251             case GLU_TESS_WINDING_RULE:
252                 int windingRule = (int) value;
253                 if (windingRule != value) break;	/* not an integer */
254 
255                 switch (windingRule) {
256                     case GLU_TESS_WINDING_ODD:
257                     case GLU_TESS_WINDING_NONZERO:
258                     case GLU_TESS_WINDING_POSITIVE:
259                     case GLU_TESS_WINDING_NEGATIVE:
260                     case GLU_TESS_WINDING_ABS_GEQ_TWO:
261                         this.windingRule = windingRule;
262                         return;
263                     default:
264                         break;
265                 }
266 
267             case GLU_TESS_BOUNDARY_ONLY:
268                 boundaryOnly = (value != 0);
269                 return;
270 
271             default:
272                 callErrorOrErrorData(GLU_INVALID_ENUM);
273                 return;
274         }
275         callErrorOrErrorData(GLU_INVALID_VALUE);
276     }
277 
278 /* Returns tessellator property */
gluGetTessProperty(int which, double[] value, int value_offset)279     public void gluGetTessProperty(int which, double[] value, int value_offset) {
280         switch (which) {
281             case GLU_TESS_TOLERANCE:
282 /* tolerance should be in range [0..1] */
283                 assert (0.0 <= relTolerance && relTolerance <= 1.0);
284                 value[value_offset] = relTolerance;
285                 break;
286             case GLU_TESS_WINDING_RULE:
287                 assert (windingRule == GLU_TESS_WINDING_ODD ||
288                         windingRule == GLU_TESS_WINDING_NONZERO ||
289                         windingRule == GLU_TESS_WINDING_POSITIVE ||
290                         windingRule == GLU_TESS_WINDING_NEGATIVE ||
291                         windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
292                 value[value_offset] = windingRule;
293                 break;
294             case GLU_TESS_BOUNDARY_ONLY:
295                 assert (boundaryOnly == true || boundaryOnly == false);
296                 value[value_offset] = boundaryOnly ? 1 : 0;
297                 break;
298             default:
299                 value[value_offset] = 0.0;
300                 callErrorOrErrorData(GLU_INVALID_ENUM);
301                 break;
302         }
303     } /* gluGetTessProperty() */
304 
gluTessNormal(double x, double y, double z)305     public void gluTessNormal(double x, double y, double z) {
306         normal[0] = x;
307         normal[1] = y;
308         normal[2] = z;
309     }
310 
gluTessCallback(int which, GLUtessellatorCallback aCallback)311     public void gluTessCallback(int which, GLUtessellatorCallback aCallback) {
312         switch (which) {
313             case GLU_TESS_BEGIN:
314                 callBegin = aCallback == null ? NULL_CB : aCallback;
315                 return;
316             case GLU_TESS_BEGIN_DATA:
317                 callBeginData = aCallback == null ? NULL_CB : aCallback;
318                 return;
319             case GLU_TESS_EDGE_FLAG:
320                 callEdgeFlag = aCallback == null ? NULL_CB : aCallback;
321 /* If the client wants boundary edges to be flagged,
322  * we render everything as separate triangles (no strips or fans).
323  */
324                 flagBoundary = aCallback != null;
325                 return;
326             case GLU_TESS_EDGE_FLAG_DATA:
327                 callEdgeFlagData = callBegin = aCallback == null ? NULL_CB : aCallback;
328 /* If the client wants boundary edges to be flagged,
329  * we render everything as separate triangles (no strips or fans).
330  */
331                 flagBoundary = (aCallback != null);
332                 return;
333             case GLU_TESS_VERTEX:
334                 callVertex = aCallback == null ? NULL_CB : aCallback;
335                 return;
336             case GLU_TESS_VERTEX_DATA:
337                 callVertexData = aCallback == null ? NULL_CB : aCallback;
338                 return;
339             case GLU_TESS_END:
340                 callEnd = aCallback == null ? NULL_CB : aCallback;
341                 return;
342             case GLU_TESS_END_DATA:
343                 callEndData = aCallback == null ? NULL_CB : aCallback;
344                 return;
345             case GLU_TESS_ERROR:
346                 callError = aCallback == null ? NULL_CB : aCallback;
347                 return;
348             case GLU_TESS_ERROR_DATA:
349                 callErrorData = aCallback == null ? NULL_CB : aCallback;
350                 return;
351             case GLU_TESS_COMBINE:
352                 callCombine = aCallback == null ? NULL_CB : aCallback;
353                 return;
354             case GLU_TESS_COMBINE_DATA:
355                 callCombineData = aCallback == null ? NULL_CB : aCallback;
356                 return;
357 //            case GLU_TESS_MESH:
358 //                callMesh = aCallback == null ? NULL_CB : aCallback;
359 //                return;
360             default:
361                 callErrorOrErrorData(GLU_INVALID_ENUM);
362                 return;
363         }
364     }
365 
addVertex(double[] coords, Object vertexData)366     private boolean addVertex(double[] coords, Object vertexData) {
367         GLUhalfEdge e;
368 
369         e = lastEdge;
370         if (e == null) {
371 /* Make a self-loop (one vertex, one edge). */
372 
373             e = Mesh.__gl_meshMakeEdge(mesh);
374             if (e == null) return false;
375             if (!Mesh.__gl_meshSplice(e, e.Sym)) return false;
376         } else {
377 /* Create a new vertex and edge which immediately follow e
378  * in the ordering around the left face.
379  */
380             if (Mesh.__gl_meshSplitEdge(e) == null) return false;
381             e = e.Lnext;
382         }
383 
384 /* The new vertex is now e.Org. */
385         e.Org.data = vertexData;
386         e.Org.coords[0] = coords[0];
387         e.Org.coords[1] = coords[1];
388         e.Org.coords[2] = coords[2];
389 
390 /* The winding of an edge says how the winding number changes as we
391  * cross from the edge''s right face to its left face.  We add the
392  * vertices in such an order that a CCW contour will add +1 to
393  * the winding number of the region inside the contour.
394  */
395         e.winding = 1;
396         e.Sym.winding = -1;
397 
398         lastEdge = e;
399 
400         return true;
401     }
402 
cacheVertex(double[] coords, Object vertexData)403     private void cacheVertex(double[] coords, Object vertexData) {
404         if (cache[cacheCount] == null) {
405             cache[cacheCount] = new CachedVertex();
406         }
407 
408         CachedVertex v = cache[cacheCount];
409 
410         v.data = vertexData;
411         v.coords[0] = coords[0];
412         v.coords[1] = coords[1];
413         v.coords[2] = coords[2];
414         ++cacheCount;
415     }
416 
417 
flushCache()418     private boolean flushCache() {
419         CachedVertex[] v = cache;
420 
421         mesh = Mesh.__gl_meshNewMesh();
422         if (mesh == null) return false;
423 
424         for (int i = 0; i < cacheCount; i++) {
425             CachedVertex vertex = v[i];
426             if (!addVertex(vertex.coords, vertex.data)) return false;
427         }
428         cacheCount = 0;
429         flushCacheOnNextVertex = false;
430 
431         return true;
432     }
433 
gluTessVertex(double[] coords, int coords_offset, Object vertexData)434     public void gluTessVertex(double[] coords, int coords_offset, Object vertexData) {
435         int i;
436         boolean tooLarge = false;
437         double x;
438         double[] clamped = new double[3];
439 
440         requireState(TessState.T_IN_CONTOUR);
441 
442         if (flushCacheOnNextVertex) {
443             if (!flushCache()) {
444                 callErrorOrErrorData(GLU_OUT_OF_MEMORY);
445                 return;
446             }
447             lastEdge = null;
448         }
449         for (i = 0; i < 3; ++i) {
450             x = coords[i+coords_offset];
451             if (x < -GLU_TESS_MAX_COORD) {
452                 x = -GLU_TESS_MAX_COORD;
453                 tooLarge = true;
454             }
455             if (x > GLU_TESS_MAX_COORD) {
456                 x = GLU_TESS_MAX_COORD;
457                 tooLarge = true;
458             }
459             clamped[i] = x;
460         }
461         if (tooLarge) {
462             callErrorOrErrorData(GLU_TESS_COORD_TOO_LARGE);
463         }
464 
465         if (mesh == null) {
466             if (cacheCount < TESS_MAX_CACHE) {
467                 cacheVertex(clamped, vertexData);
468                 return;
469             }
470             if (!flushCache()) {
471                 callErrorOrErrorData(GLU_OUT_OF_MEMORY);
472                 return;
473             }
474         }
475 
476         if (!addVertex(clamped, vertexData)) {
477             callErrorOrErrorData(GLU_OUT_OF_MEMORY);
478         }
479     }
480 
481 
gluTessBeginPolygon(Object data)482     public void gluTessBeginPolygon(Object data) {
483         requireState(TessState.T_DORMANT);
484 
485         state = TessState.T_IN_POLYGON;
486         cacheCount = 0;
487         flushCacheOnNextVertex = false;
488         mesh = null;
489 
490         polygonData = data;
491     }
492 
493 
gluTessBeginContour()494     public void gluTessBeginContour() {
495         requireState(TessState.T_IN_POLYGON);
496 
497         state = TessState.T_IN_CONTOUR;
498         lastEdge = null;
499         if (cacheCount > 0) {
500 /* Just set a flag so we don't get confused by empty contours
501  * -- these can be generated accidentally with the obsolete
502  * NextContour() interface.
503  */
504             flushCacheOnNextVertex = true;
505         }
506     }
507 
508 
gluTessEndContour()509     public void gluTessEndContour() {
510         requireState(TessState.T_IN_CONTOUR);
511         state = TessState.T_IN_POLYGON;
512     }
513 
gluTessEndPolygon()514     public void gluTessEndPolygon() {
515         GLUmesh mesh;
516 
517         try {
518             requireState(TessState.T_IN_POLYGON);
519             state = TessState.T_DORMANT;
520 
521             if (this.mesh == null) {
522                 if (!flagBoundary /*&& callMesh == NULL_CB*/) {
523 
524 /* Try some special code to make the easy cases go quickly
525  * (eg. convex polygons).  This code does NOT handle multiple contours,
526  * intersections, edge flags, and of course it does not generate
527  * an explicit mesh either.
528  */
529                     if (Render.__gl_renderCache(this)) {
530                         polygonData = null;
531                         return;
532                     }
533                 }
534                 if (!flushCache()) throw new RuntimeException(); /* could've used a label*/
535             }
536 
537 /* Determine the polygon normal and project vertices onto the plane
538          * of the polygon.
539          */
540             Normal.__gl_projectPolygon(this);
541 
542 /* __gl_computeInterior( tess ) computes the planar arrangement specified
543  * by the given contours, and further subdivides this arrangement
544  * into regions.  Each region is marked "inside" if it belongs
545  * to the polygon, according to the rule given by windingRule.
546  * Each interior region is guaranteed be monotone.
547  */
548             if (!Sweep.__gl_computeInterior(this)) {
549                 throw new RuntimeException();	/* could've used a label */
550             }
551 
552             mesh = this.mesh;
553             if (!fatalError) {
554                 boolean rc = true;
555 
556 /* If the user wants only the boundary contours, we throw away all edges
557  * except those which separate the interior from the exterior.
558  * Otherwise we tessellate all the regions marked "inside".
559  */
560                 if (boundaryOnly) {
561                     rc = TessMono.__gl_meshSetWindingNumber(mesh, 1, true);
562                 } else {
563                     rc = TessMono.__gl_meshTessellateInterior(mesh);
564                 }
565                 if (!rc) throw new RuntimeException();	/* could've used a label */
566 
567                 Mesh.__gl_meshCheckMesh(mesh);
568 
569                 if (callBegin != NULL_CB || callEnd != NULL_CB
570                         || callVertex != NULL_CB || callEdgeFlag != NULL_CB
571                         || callBeginData != NULL_CB
572                         || callEndData != NULL_CB
573                         || callVertexData != NULL_CB
574                         || callEdgeFlagData != NULL_CB) {
575                     if (boundaryOnly) {
576                         Render.__gl_renderBoundary(this, mesh);  /* output boundary contours */
577                     } else {
578                         Render.__gl_renderMesh(this, mesh);	   /* output strips and fans */
579                     }
580                 }
581 //                if (callMesh != NULL_CB) {
582 //
583 ///* Throw away the exterior faces, so that all faces are interior.
584 //                 * This way the user doesn't have to check the "inside" flag,
585 //                 * and we don't need to even reveal its existence.  It also leaves
586 //                 * the freedom for an implementation to not generate the exterior
587 //                 * faces in the first place.
588 //                 */
589 //                    TessMono.__gl_meshDiscardExterior(mesh);
590 //                    callMesh.mesh(mesh);		/* user wants the mesh itself */
591 //                    mesh = null;
592 //                    polygonData = null;
593 //                    return;
594 //                }
595             }
596             Mesh.__gl_meshDeleteMesh(mesh);
597             polygonData = null;
598             mesh = null;
599         } catch (Exception e) {
600             e.printStackTrace();
601             callErrorOrErrorData(GLU_OUT_OF_MEMORY);
602         }
603     }
604 
605     /*******************************************************/
606 
607 /* Obsolete calls -- for backward compatibility */
608 
gluBeginPolygon()609     public void gluBeginPolygon() {
610         gluTessBeginPolygon(null);
611         gluTessBeginContour();
612     }
613 
614 
615 /*ARGSUSED*/
gluNextContour(int type)616     public void gluNextContour(int type) {
617         gluTessEndContour();
618         gluTessBeginContour();
619     }
620 
621 
gluEndPolygon()622     public void gluEndPolygon() {
623         gluTessEndContour();
624         gluTessEndPolygon();
625     }
626 
callBeginOrBeginData(int a)627     void callBeginOrBeginData(int a) {
628         if (callBeginData != NULL_CB)
629             callBeginData.beginData(a, polygonData);
630         else
631             callBegin.begin(a);
632     }
633 
callVertexOrVertexData(Object a)634     void callVertexOrVertexData(Object a) {
635         if (callVertexData != NULL_CB)
636             callVertexData.vertexData(a, polygonData);
637         else
638             callVertex.vertex(a);
639     }
640 
callEdgeFlagOrEdgeFlagData(boolean a)641     void callEdgeFlagOrEdgeFlagData(boolean a) {
642         if (callEdgeFlagData != NULL_CB)
643             callEdgeFlagData.edgeFlagData(a, polygonData);
644         else
645             callEdgeFlag.edgeFlag(a);
646     }
647 
callEndOrEndData()648     void callEndOrEndData() {
649         if (callEndData != NULL_CB)
650             callEndData.endData(polygonData);
651         else
652             callEnd.end();
653     }
654 
callCombineOrCombineData(double[] coords, Object[] vertexData, float[] weights, Object[] outData)655     void callCombineOrCombineData(double[] coords, Object[] vertexData, float[] weights, Object[] outData) {
656         if (callCombineData != NULL_CB)
657             callCombineData.combineData(coords, vertexData, weights, outData, polygonData);
658         else
659             callCombine.combine(coords, vertexData, weights, outData);
660     }
661 
callErrorOrErrorData(int a)662     void callErrorOrErrorData(int a) {
663         if (callErrorData != NULL_CB)
664             callErrorData.errorData(a, polygonData);
665         else
666             callError.error(a);
667     }
668 
669 }
670