mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	WIP Added libtess library extracted from
https://cgit.freedesktop.org/mesa/glu/ The library is stable (it should be, since it is in use since 1994), but it is not thread safe: Its callbacks do not receive any pointer to a context.
This commit is contained in:
		
							parent
							
								
									a35b1a1850
								
							
						
					
					
						commit
						f797083ca2
					
				
					 32 changed files with 7072 additions and 0 deletions
				
			
		|  | @ -6,6 +6,7 @@ add_subdirectory(avrdude) | |||
| add_subdirectory(boost) | ||||
| add_subdirectory(clipper) | ||||
| add_subdirectory(miniz) | ||||
| add_subdirectory(glu-libtess) | ||||
| add_subdirectory(polypartition) | ||||
| add_subdirectory(poly2tri) | ||||
| add_subdirectory(qhull) | ||||
|  |  | |||
							
								
								
									
										36
									
								
								src/glu-libtess/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/glu-libtess/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| project(glu-libtess) | ||||
| cmake_minimum_required(VERSION 2.6) | ||||
| 
 | ||||
| add_library(glu-libtess STATIC  | ||||
| 	src/dict-list.h | ||||
| 	src/dict.c | ||||
| 	src/dict.h | ||||
| 	src/geom.c | ||||
| 	src/geom.h | ||||
| 	src/gluos.h | ||||
| 	src/memalloc.c | ||||
| 	src/memalloc.h | ||||
| 	src/mesh.c | ||||
| 	src/mesh.h | ||||
| 	src/normal.c | ||||
| 	src/normal.h | ||||
| 	src/priorityq.c | ||||
| 	src/priorityq.h | ||||
| 	src/priorityq-heap.h | ||||
| 	src/priorityq-sort.h | ||||
| 	src/render.c | ||||
| 	src/render.h | ||||
| 	src/sweep.c | ||||
| 	src/sweep.h | ||||
| 	src/tess.c | ||||
| 	src/tess.h | ||||
| 	src/tessmono.c | ||||
| 	src/tessmono.h | ||||
| 	include/glu-libtess.h | ||||
| 	) | ||||
| 
 | ||||
| if(UNIX) | ||||
|     target_link_libraries(glu-libtess m) | ||||
| endif(UNIX) | ||||
| 
 | ||||
| target_include_directories(glu-libtess PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) | ||||
							
								
								
									
										24
									
								
								src/glu-libtess/README
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/glu-libtess/README
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| Derived from  | ||||
| https://cgit.freedesktop.org/mesa/glu/ | ||||
| commit 0bf42e41c8b63fc2488dd8d41f696310b5a5a6a7 | ||||
| Fri Jun 10 05:30:00 2016 | ||||
| 
 | ||||
| This directory contains just the libtess tesselation library to be statically compilable without OpenGL dependencies. | ||||
| Only the following functions are provided, and mangled: | ||||
| 
 | ||||
| mgluNewTess | ||||
| mgluDeleteTess | ||||
| mgluTessBeginPolygon | ||||
| mgluTessBeginContour | ||||
| mgluTessVertex | ||||
| mgluTessEndPolygon | ||||
| mgluTessEndContour | ||||
| mgluTessProperty | ||||
| mgluTessNormal | ||||
| mgluTessCallback | ||||
| mgluGetTessProperty | ||||
| mgluBeginPolygon | ||||
| mgluNextContour | ||||
| mgluEndPolygon | ||||
| 
 | ||||
| Do include gl.h, glu.h or glut.h together with glu-libtess.h, you would get symbol clashes! | ||||
							
								
								
									
										197
									
								
								src/glu-libtess/include/glu-libtess.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/glu-libtess/include/glu-libtess.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,197 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __glu_libtess_h__ | ||||
| #define __glu_libtess_h__ | ||||
| 
 | ||||
| #define USE_MGL_NAMESPACE | ||||
| 
 | ||||
| #define gluNewTess mgluNewTess | ||||
| #define gluDeleteTess mgluDeleteTess | ||||
| #define gluTessBeginPolygon mgluTessBeginPolygon | ||||
| #define gluTessBeginContour mgluTessBeginContour | ||||
| #define gluTessVertex mgluTessVertex | ||||
| #define gluTessEndPolygon mgluTessEndPolygon | ||||
| #define gluTessEndContour mgluTessEndContour | ||||
| #define gluTessProperty mgluTessProperty | ||||
| #define gluTessNormal mgluTessNormal | ||||
| #define gluTessCallback mgluTessCallback | ||||
| #define gluGetTessProperty mgluGetTessProperty | ||||
| #define gluBeginPolygon mgluBeginPolygon | ||||
| #define gluNextContour mgluNextContour | ||||
| #define gluEndPolygon mgluEndPolygon | ||||
| 
 | ||||
| #define GLAPI extern | ||||
| #define GLAPIENTRY | ||||
| typedef unsigned int GLenum; | ||||
| typedef unsigned char GLboolean; | ||||
| typedef unsigned int GLbitfield; | ||||
| typedef signed char GLbyte; | ||||
| typedef short GLshort; | ||||
| typedef int GLint; | ||||
| typedef int GLsizei; | ||||
| typedef unsigned char GLubyte; | ||||
| typedef unsigned short GLushort; | ||||
| typedef unsigned int GLuint; | ||||
| typedef float GLfloat; | ||||
| typedef float GLclampf; | ||||
| typedef double GLdouble; | ||||
| typedef double GLclampd; | ||||
| typedef void GLvoid; | ||||
| 
 | ||||
| /* Boolean */ | ||||
| #define GL_TRUE                           1 | ||||
| #define GL_FALSE                          0 | ||||
| 
 | ||||
| /* BeginMode */ | ||||
| #define GL_LINE_LOOP                      0x0002 | ||||
| #define GL_TRIANGLES                      0x0004 | ||||
| #define GL_TRIANGLE_STRIP                 0x0005 | ||||
| #define GL_TRIANGLE_FAN                   0x0006 | ||||
| 
 | ||||
| #ifndef GLAPIENTRYP | ||||
| #define GLAPIENTRYP GLAPIENTRY * | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __glu_h__ | ||||
| static_assert(false, "glu-libtess.h: glu.h must not be included!") | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __gl_h__ | ||||
| static_assert(false, "glu-libtess.h: gl.h must not be included!") | ||||
| #endif | ||||
| 
 | ||||
| /*************************************************************/ | ||||
| 
 | ||||
| /* StringName */ | ||||
| #define GLU_VERSION                        100800 | ||||
| #define GLU_EXTENSIONS                     100801 | ||||
| 
 | ||||
| /* ErrorCode */ | ||||
| #define GLU_INVALID_ENUM                   100900 | ||||
| #define GLU_INVALID_VALUE                  100901 | ||||
| #define GLU_OUT_OF_MEMORY                  100902 | ||||
| #define GLU_INCOMPATIBLE_GL_VERSION        100903 | ||||
| #define GLU_INVALID_OPERATION              100904 | ||||
| 
 | ||||
| /* TessCallback */ | ||||
| #define GLU_TESS_BEGIN                     100100 | ||||
| #define GLU_BEGIN                          100100 | ||||
| #define GLU_TESS_VERTEX                    100101 | ||||
| #define GLU_VERTEX                         100101 | ||||
| #define GLU_TESS_END                       100102 | ||||
| #define GLU_END                            100102 | ||||
| #define GLU_TESS_ERROR                     100103 | ||||
| #define GLU_TESS_EDGE_FLAG                 100104 | ||||
| #define GLU_EDGE_FLAG                      100104 | ||||
| #define GLU_TESS_COMBINE                   100105 | ||||
| #define GLU_TESS_BEGIN_DATA                100106 | ||||
| #define GLU_TESS_VERTEX_DATA               100107 | ||||
| #define GLU_TESS_END_DATA                  100108 | ||||
| #define GLU_TESS_ERROR_DATA                100109 | ||||
| #define GLU_TESS_EDGE_FLAG_DATA            100110 | ||||
| #define GLU_TESS_COMBINE_DATA              100111 | ||||
| 
 | ||||
| /* TessContour */ | ||||
| #define GLU_CW                             100120 | ||||
| #define GLU_CCW                            100121 | ||||
| #define GLU_INTERIOR                       100122 | ||||
| #define GLU_EXTERIOR                       100123 | ||||
| #define GLU_UNKNOWN                        100124 | ||||
| 
 | ||||
| /* TessProperty */ | ||||
| #define GLU_TESS_WINDING_RULE              100140 | ||||
| #define GLU_TESS_BOUNDARY_ONLY             100141 | ||||
| #define GLU_TESS_TOLERANCE                 100142 | ||||
| 
 | ||||
| /* TessError */ | ||||
| #define GLU_TESS_ERROR1                    100151 | ||||
| #define GLU_TESS_ERROR2                    100152 | ||||
| #define GLU_TESS_ERROR3                    100153 | ||||
| #define GLU_TESS_ERROR4                    100154 | ||||
| #define GLU_TESS_ERROR5                    100155 | ||||
| #define GLU_TESS_ERROR6                    100156 | ||||
| #define GLU_TESS_ERROR7                    100157 | ||||
| #define GLU_TESS_ERROR8                    100158 | ||||
| #define GLU_TESS_MISSING_BEGIN_POLYGON     100151 | ||||
| #define GLU_TESS_MISSING_BEGIN_CONTOUR     100152 | ||||
| #define GLU_TESS_MISSING_END_POLYGON       100153 | ||||
| #define GLU_TESS_MISSING_END_CONTOUR       100154 | ||||
| #define GLU_TESS_COORD_TOO_LARGE           100155 | ||||
| #define GLU_TESS_NEED_COMBINE_CALLBACK     100156 | ||||
| 
 | ||||
| /* TessWinding */ | ||||
| #define GLU_TESS_WINDING_ODD               100130 | ||||
| #define GLU_TESS_WINDING_NONZERO           100131 | ||||
| #define GLU_TESS_WINDING_POSITIVE          100132 | ||||
| #define GLU_TESS_WINDING_NEGATIVE          100133 | ||||
| #define GLU_TESS_WINDING_ABS_GEQ_TWO       100134 | ||||
| 
 | ||||
| /*************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| class GLUtesselator; | ||||
| #else | ||||
| typedef struct GLUtesselator GLUtesselator; | ||||
| #endif | ||||
| 
 | ||||
| typedef GLUtesselator GLUtesselatorObj; | ||||
| typedef GLUtesselator GLUtriangulatorObj; | ||||
| 
 | ||||
| #define GLU_TESS_MAX_COORD 1.0e150 | ||||
| 
 | ||||
| /* Internal convenience typedefs */ | ||||
| typedef void (GLAPIENTRYP _GLUfuncptr)(void); | ||||
| 
 | ||||
| GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data); | ||||
| GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void); | ||||
| GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type); | ||||
| GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data); | ||||
| GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc); | ||||
| GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess); | ||||
| GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ); | ||||
| GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data); | ||||
| GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __glu_libtess_h__ */ | ||||
							
								
								
									
										446
									
								
								src/glu-libtess/src/README
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										446
									
								
								src/glu-libtess/src/README
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,446 @@ | |||
| /* | ||||
| */ | ||||
| 
 | ||||
| General Polygon Tesselation | ||||
| --------------------------- | ||||
| 
 | ||||
|   This note describes a tesselator for polygons consisting of one or | ||||
|   more closed contours.  It is backward-compatible with the current | ||||
|   OpenGL Utilities tesselator, and is intended to replace it.  Here is | ||||
|   a summary of the major differences: | ||||
| 
 | ||||
|    - input contours can be intersecting, self-intersecting, or degenerate. | ||||
|    | ||||
|    - supports a choice of several winding rules for determining which parts | ||||
|      of the polygon are on the "interior".  This makes it possible to do | ||||
|      CSG operations on polygons. | ||||
|    | ||||
|    - boundary extraction: instead of tesselating the polygon, returns a | ||||
|      set of closed contours which separate the interior from the exterior. | ||||
|    | ||||
|    - returns the output as a small number of triangle fans and strips, | ||||
|      rather than a list of independent triangles (when possible). | ||||
|    | ||||
|    - output is available as an explicit mesh (a quad-edge structure), | ||||
|      in addition to the normal callback interface. | ||||
|    | ||||
|    - the algorithm used is extremely robust. | ||||
| 
 | ||||
| 
 | ||||
| The interface | ||||
| ------------- | ||||
| 
 | ||||
|   The tesselator state is maintained in a "tesselator object". | ||||
|   These are allocated and destroyed using | ||||
| 
 | ||||
|      GLUtesselator *gluNewTess( void ); | ||||
|      void gluDeleteTess( GLUtesselator *tess ); | ||||
| 
 | ||||
|   Several tesselator objects may be used simultaneously. | ||||
| 
 | ||||
|   Inputs | ||||
|   ------ | ||||
|    | ||||
|   The input contours are specified with the following routines: | ||||
| 
 | ||||
|      void gluTessBeginPolygon( GLUtesselator *tess ); | ||||
|      void gluTessBeginContour( GLUtesselator *tess ); | ||||
|      void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data ); | ||||
|      void gluTessEndContour( GLUtesselator *tess ); | ||||
|      void gluTessEndPolygon( GLUtesselator *tess ); | ||||
| 
 | ||||
|   Within each BeginPolygon/EndPolygon pair, there can be zero or more | ||||
|   calls to BeginContour/EndContour.  Within each contour, there are zero | ||||
|   or more calls to gluTessVertex().  The vertices specify a closed | ||||
|   contour (the last vertex of each contour is automatically linked to | ||||
|   the first). | ||||
| 
 | ||||
|   "coords" give the coordinates of the vertex in 3-space.  For useful | ||||
|   results, all vertices should lie in some plane, since the vertices | ||||
|   are projected onto a plane before tesselation.  "data" is a pointer | ||||
|   to a user-defined vertex structure, which typically contains other | ||||
|   information such as color, texture coordinates, normal, etc.  It is | ||||
|   used to refer to the vertex during rendering. | ||||
| 
 | ||||
|   The library can be compiled in single- or double-precision; the type | ||||
|   GLUcoord represents either "float" or "double" accordingly.  The GLU | ||||
|   version will be available in double-precision only.  Compile with | ||||
|   GLU_TESS_API_FLOAT defined to get the single-precision version. | ||||
| 
 | ||||
|   When EndPolygon is called, the tesselation algorithm determines | ||||
|   which regions are interior to the given contours, according to one | ||||
|   of several "winding rules" described below.  The interior regions | ||||
|   are then tesselated, and the output is provided as callbacks. | ||||
| 
 | ||||
| 
 | ||||
|   Rendering Callbacks | ||||
|   ------------------- | ||||
| 
 | ||||
|   Callbacks are specified by the client using | ||||
| 
 | ||||
|      void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)()); | ||||
| 
 | ||||
|   If "fn" is NULL, any previously defined callback is discarded. | ||||
|    | ||||
|   The callbacks used to provide output are:	/* which == */ | ||||
| 
 | ||||
|      void begin( GLenum type );			/* GLU_TESS_BEGIN */ | ||||
|      void edgeFlag( GLboolean flag );		/* GLU_TESS_EDGE_FLAG */ | ||||
|      void vertex( void *data );			/* GLU_TESS_VERTEX */ | ||||
|      void end( void );				/* GLU_TESS_END */ | ||||
| 
 | ||||
|   Any of the callbacks may be left undefined; if so, the corresponding | ||||
|   information will not be supplied during rendering. | ||||
| 
 | ||||
|   The "begin" callback indicates the start of a primitive; type is one | ||||
|   of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the | ||||
|   notes on "boundary extraction" below). | ||||
|    | ||||
|   It is followed by any number of "vertex" callbacks, which supply the | ||||
|   vertices in the same order as expected by the corresponding glBegin() | ||||
|   call.  After the last vertex of a given primitive, there is a callback | ||||
|   to "end". | ||||
| 
 | ||||
|   If the "edgeFlag" callback is provided, no triangle fans or strips | ||||
|   will be used.  When edgeFlag is called, if "flag" is GL_TRUE then each | ||||
|   vertex which follows begins an edge which lies on the polygon boundary | ||||
|   (ie. an edge which separates an interior region from an exterior one). | ||||
|   If "flag" is GL_FALSE, each vertex which follows begins an edge which lies | ||||
|   in the polygon interior.  "edgeFlag" will be called before the first | ||||
|   call to "vertex". | ||||
| 
 | ||||
|   Other Callbacks | ||||
|   --------------- | ||||
| 
 | ||||
|    void mesh( GLUmesh *mesh );			/* GLU_TESS_MESH */ | ||||
| 
 | ||||
|    - Returns an explicit mesh, represented using the quad-edge structure | ||||
|      (Guibas/Stolfi '85).  Other implementations of this interface might | ||||
|      use a different mesh structure, so this is available only only as an | ||||
|      SGI extension.  When the mesh is no longer needed, it should be freed | ||||
|      using | ||||
| 
 | ||||
| 	void gluDeleteMesh( GLUmesh *mesh ); | ||||
| 
 | ||||
|      There is a brief description of this data structure in the include | ||||
|      file "mesh.h".  For the full details, see L. Guibas and J. Stolfi, | ||||
|      Primitives for the manipulation of general subdivisions and the | ||||
|      computation of Voronoi diagrams, ACM Transactions on Graphics, | ||||
|      4(2):74-123, April 1985.  For an introduction, see the course notes | ||||
|      for CS348a, "Mathematical Foundations of Computer Graphics", | ||||
|      available at the Stanford bookstore (and taught during the fall | ||||
|      quarter). | ||||
| 
 | ||||
|    void error( GLenum errno );			/* GLU_TESS_ERROR */ | ||||
| 
 | ||||
|    - errno is one of	GLU_TESS_MISSING_BEGIN_POLYGON, | ||||
| 			GLU_TESS_MISSING_END_POLYGON, | ||||
| 			GLU_TESS_MISSING_BEGIN_CONTOUR, | ||||
| 			GLU_TESS_MISSING_END_CONTOUR, | ||||
| 			GLU_TESS_COORD_TOO_LARGE, | ||||
| 			GLU_TESS_NEED_COMBINE_CALLBACK | ||||
| 
 | ||||
|      The first four are obvious.  The interface recovers from these | ||||
|      errors by inserting the missing call(s). | ||||
|    | ||||
|      GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded | ||||
|      the predefined constant GLU_TESS_MAX_COORD in absolute value, and | ||||
|      that the value has been clamped.  (Coordinate values must be small | ||||
|      enough so that two can be multiplied together without overflow.) | ||||
| 
 | ||||
|      GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an | ||||
|      intersection between two edges in the input data, and the "combine" | ||||
|      callback (below) was not provided.  No output will be generated. | ||||
| 
 | ||||
| 
 | ||||
|    void combine( GLUcoord coords[3], void *data[4],	/* GLU_TESS_COMBINE */ | ||||
| 		 GLUcoord weight[4], void **outData ); | ||||
| 
 | ||||
|    - When the algorithm detects an intersection, or wishes to merge | ||||
|      features, it needs to create a new vertex.  The vertex is defined | ||||
|      as a linear combination of up to 4 existing vertices, referenced | ||||
|      by data[0..3].  The coefficients of the linear combination are | ||||
|      given by weight[0..3]; these weights always sum to 1.0.  All vertex | ||||
|      pointers are valid even when some of the weights are zero. | ||||
|      "coords" gives the location of the new vertex. | ||||
| 
 | ||||
|      The user must allocate another vertex, interpolate parameters | ||||
|      using "data" and "weights", and return the new vertex pointer in | ||||
|      "outData".  This handle is supplied during rendering callbacks. | ||||
|      For example, if the polygon lies in an arbitrary plane in 3-space, | ||||
|      and we associate a color with each vertex, the combine callback might | ||||
|      look like this: | ||||
|      | ||||
|      void myCombine( GLUcoord coords[3], VERTEX *d[4], | ||||
|                      GLUcoord w[4], VERTEX **dataOut ) | ||||
|      { | ||||
|         VERTEX *new = new_vertex(); | ||||
|         | ||||
|         new->x = coords[0]; | ||||
|         new->y = coords[1]; | ||||
|         new->z = coords[2]; | ||||
|         new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r; | ||||
|         new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g; | ||||
|         new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b; | ||||
|         new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a; | ||||
|         *dataOut = new; | ||||
|      } | ||||
| 
 | ||||
|      If the algorithm detects an intersection, then the "combine" callback | ||||
|      must be defined, and must write a non-NULL pointer into "dataOut". | ||||
|      Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no | ||||
|      output is generated.  This is the only error that can occur during | ||||
|      tesselation and rendering. | ||||
| 
 | ||||
| 
 | ||||
|   Control over Tesselation | ||||
|   ------------------------ | ||||
|    | ||||
|    void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value ); | ||||
| 
 | ||||
|    Properties defined: | ||||
| 
 | ||||
|     - GLU_TESS_WINDING_RULE.  Possible values: | ||||
| 
 | ||||
| 	  GLU_TESS_WINDING_ODD | ||||
| 	  GLU_TESS_WINDING_NONZERO | ||||
| 	  GLU_TESS_WINDING_POSITIVE | ||||
| 	  GLU_TESS_WINDING_NEGATIVE | ||||
| 	  GLU_TESS_WINDING_ABS_GEQ_TWO | ||||
| 
 | ||||
|       The input contours parition the plane into regions.  A winding | ||||
|       rule determines which of these regions are inside the polygon. | ||||
|        | ||||
|       For a single contour C, the winding number of a point x is simply | ||||
|       the signed number of revolutions we make around x as we travel | ||||
|       once around C (where CCW is positive).  When there are several | ||||
|       contours, the individual winding numbers are summed.  This | ||||
|       procedure associates a signed integer value with each point x in | ||||
|       the plane.  Note that the winding number is the same for all | ||||
|       points in a single region. | ||||
| 
 | ||||
|       The winding rule classifies a region as "inside" if its winding | ||||
|       number belongs to the chosen category (odd, nonzero, positive, | ||||
|       negative, or absolute value of at least two).  The current GLU | ||||
|       tesselator implements the "odd" rule.  The "nonzero" rule is another | ||||
|       common way to define the interior.  The other three rules are | ||||
|       useful for polygon CSG operations (see below). | ||||
| 
 | ||||
|     - GLU_TESS_BOUNDARY_ONLY.  Values: TRUE (non-zero) or FALSE (zero). | ||||
| 
 | ||||
|       If TRUE, returns a set of closed contours which separate the | ||||
|       polygon interior and exterior (rather than a tesselation). | ||||
|       Exterior contours are oriented CCW with respect to the normal, | ||||
|       interior contours are oriented CW.  The GLU_TESS_BEGIN callback | ||||
|       uses the type GL_LINE_LOOP for each contour. | ||||
|        | ||||
|     - GLU_TESS_TOLERANCE.  Value: a real number between 0.0 and 1.0. | ||||
| 
 | ||||
|       This specifies a tolerance for merging features to reduce the size | ||||
|       of the output.  For example, two vertices which are very close to | ||||
|       each other might be replaced by a single vertex.  The tolerance | ||||
|       is multiplied by the largest coordinate magnitude of any input vertex; | ||||
|       this specifies the maximum distance that any feature can move as the | ||||
|       result of a single merge operation.  If a single feature takes part | ||||
|       in several merge operations, the total distance moved could be larger. | ||||
| 
 | ||||
|       Feature merging is completely optional; the tolerance is only a hint. | ||||
|       The implementation is free to merge in some cases and not in others, | ||||
|       or to never merge features at all.  The default tolerance is zero. | ||||
|        | ||||
|       The current implementation merges vertices only if they are exactly | ||||
|       coincident, regardless of the current tolerance.  A vertex is | ||||
|       spliced into an edge only if the implementation is unable to | ||||
|       distinguish which side of the edge the vertex lies on. | ||||
|       Two edges are merged only when both endpoints are identical. | ||||
| 
 | ||||
| 
 | ||||
|    void gluTessNormal( GLUtesselator *tess, | ||||
| 		      GLUcoord x, GLUcoord y, GLUcoord z ) | ||||
| 
 | ||||
|     - Lets the user supply the polygon normal, if known.  All input data | ||||
|       is projected into a plane perpendicular to the normal before | ||||
|       tesselation.  All output triangles are oriented CCW with | ||||
|       respect to the normal (CW orientation can be obtained by | ||||
|       reversing the sign of the supplied normal).  For example, if | ||||
|       you know that all polygons lie in the x-y plane, call | ||||
|       "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons. | ||||
|        | ||||
|     - If the supplied normal is (0,0,0) (the default value), the | ||||
|       normal is determined as follows.  The direction of the normal, | ||||
|       up to its sign, is found by fitting a plane to the vertices, | ||||
|       without regard to how the vertices are connected.  It is | ||||
|       expected that the input data lies approximately in plane; | ||||
|       otherwise projection perpendicular to the computed normal may | ||||
|       substantially change the geometry.  The sign of the normal is | ||||
|       chosen so that the sum of the signed areas of all input contours | ||||
|       is non-negative (where a CCW contour has positive area). | ||||
|      | ||||
|     - The supplied normal persists until it is changed by another | ||||
|       call to gluTessNormal. | ||||
| 
 | ||||
| 
 | ||||
|   Backward compatibility with the GLU tesselator | ||||
|   ---------------------------------------------- | ||||
| 
 | ||||
|   The preferred interface is the one described above.  The following | ||||
|   routines are obsolete, and are provided only for backward compatibility: | ||||
| 
 | ||||
|     typedef GLUtesselator GLUtriangulatorObj;	/* obsolete name */ | ||||
| 
 | ||||
|     void gluBeginPolygon( GLUtesselator *tess ); | ||||
|     void gluNextContour( GLUtesselator *tess, GLenum type ); | ||||
|     void gluEndPolygon( GLUtesselator *tess ); | ||||
|    | ||||
|   "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or | ||||
|   GLU_UNKNOWN.  It is ignored by the current GLU tesselator. | ||||
|    | ||||
|   GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined | ||||
|   as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END, | ||||
|   GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG. | ||||
| 
 | ||||
| 
 | ||||
| Polygon CSG operations | ||||
| ---------------------- | ||||
| 
 | ||||
|   The features of the tesselator make it easy to find the union, difference, | ||||
|   or intersection of several polygons. | ||||
| 
 | ||||
|   First, assume that each polygon is defined so that the winding number | ||||
|   is 0 for each exterior region, and 1 for each interior region.  Under | ||||
|   this model, CCW contours define the outer boundary of the polygon, and | ||||
|   CW contours define holes.  Contours may be nested, but a nested | ||||
|   contour must be oriented oppositely from the contour that contains it. | ||||
| 
 | ||||
|   If the original polygons do not satisfy this description, they can be | ||||
|   converted to this form by first running the tesselator with the | ||||
|   GLU_TESS_BOUNDARY_ONLY property turned on.  This returns a list of | ||||
|   contours satisfying the restriction above.  By allocating two | ||||
|   tesselator objects, the callbacks from one tesselator can be fed | ||||
|   directly to the input of another. | ||||
| 
 | ||||
|   Given two or more polygons of the form above, CSG operations can be | ||||
|   implemented as follows: | ||||
| 
 | ||||
|   Union | ||||
|      Draw all the input contours as a single polygon.  The winding number | ||||
|      of each resulting region is the number of original polygons | ||||
|      which cover it.  The union can be extracted using the | ||||
|      GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules. | ||||
|      Note that with the nonzero rule, we would get the same result if | ||||
|      all contour orientations were reversed. | ||||
| 
 | ||||
|   Intersection (two polygons at a time only) | ||||
|      Draw a single polygon using the contours from both input polygons. | ||||
|      Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO.  (Since this | ||||
|      winding rule looks at the absolute value, reversing all contour | ||||
|      orientations does not change the result.) | ||||
| 
 | ||||
|   Difference | ||||
|    | ||||
|      Suppose we want to compute A \ (B union C union D).  Draw a single | ||||
|      polygon consisting of the unmodified contours from A, followed by | ||||
|      the contours of B,C,D with the vertex order reversed (this changes | ||||
|      the winding number of the interior regions to -1).  To extract the | ||||
|      result, use the GLU_TESS_WINDING_POSITIVE rule. | ||||
|     | ||||
|      If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an | ||||
|      alternative to reversing the vertex order is to reverse the sign of | ||||
|      the supplied normal.  For example in the x-y plane, call | ||||
|      gluTessNormal( tess, 0.0, 0.0, -1.0 ). | ||||
|   | ||||
| 
 | ||||
| Performance | ||||
| ----------- | ||||
| 
 | ||||
|   The tesselator is not intended for immediate-mode rendering; when | ||||
|   possible the output should be cached in a user structure or display | ||||
|   list.  General polygon tesselation is an inherently difficult problem, | ||||
|   especially given the goal of extreme robustness. | ||||
| 
 | ||||
|   The implementation makes an effort to output a small number of fans | ||||
|   and strips; this should improve the rendering performance when the | ||||
|   output is used in a display list. | ||||
| 
 | ||||
|   Single-contour input polygons are first tested to see whether they can | ||||
|   be rendered as a triangle fan with respect to the first vertex (to | ||||
|   avoid running the full decomposition algorithm on convex polygons). | ||||
|   Non-convex polygons may be rendered by this "fast path" as well, if | ||||
|   the algorithm gets lucky in its choice of a starting vertex. | ||||
| 
 | ||||
|   For best performance follow these guidelines: | ||||
| 
 | ||||
|    - supply the polygon normal, if available, using gluTessNormal(). | ||||
|      This represents about 10% of the computation time.  For example, | ||||
|      if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1). | ||||
| 
 | ||||
|    - render many polygons using the same tesselator object, rather than | ||||
|      allocating a new tesselator for each one.  (In a multi-threaded, | ||||
|      multi-processor environment you may get better performance using | ||||
|      several tesselators.) | ||||
| 
 | ||||
| 
 | ||||
| Comparison with the GLU tesselator | ||||
| ---------------------------------- | ||||
| 
 | ||||
|   On polygons which make it through the "fast path", the tesselator is | ||||
|   3 to 5 times faster than the GLU tesselator. | ||||
| 
 | ||||
|   On polygons which don't make it through the fast path (but which don't | ||||
|   have self-intersections or degeneracies), it is about 2 times slower. | ||||
| 
 | ||||
|   On polygons with self-intersections or degeneraces, there is nothing | ||||
|   to compare against. | ||||
| 
 | ||||
|   The new tesselator generates many more fans and strips, reducing the | ||||
|   number of vertices that need to be sent to the hardware. | ||||
| 
 | ||||
|   Key to the statistics: | ||||
| 
 | ||||
| 	vert		number of input vertices on all contours | ||||
| 	cntr		number of input contours | ||||
| 	tri		number of triangles in all output primitives | ||||
| 	strip		number of triangle strips | ||||
| 	fan		number of triangle fans | ||||
| 	ind		number of independent triangles | ||||
| 	ms		number of milliseconds for tesselation | ||||
| 			(on a 150MHz R4400 Indy) | ||||
| 
 | ||||
|   Convex polygon examples: | ||||
| 
 | ||||
| New:     3 vert,   1 cntr,     1 tri,   0 strip,   0 fan,     1 ind,  0.0459 ms | ||||
| Old:     3 vert,   1 cntr,     1 tri,   0 strip,   0 fan,     1 ind,   0.149 ms | ||||
| New:     4 vert,   1 cntr,     2 tri,   0 strip,   1 fan,     0 ind,  0.0459 ms | ||||
| Old:     4 vert,   1 cntr,     2 tri,   0 strip,   0 fan,     2 ind,   0.161 ms | ||||
| New:    36 vert,   1 cntr,    34 tri,   0 strip,   1 fan,     0 ind,   0.153 ms | ||||
| Old:    36 vert,   1 cntr,    34 tri,   0 strip,   0 fan,    34 ind,   0.621 ms | ||||
| 
 | ||||
|   Concave single-contour polygons: | ||||
| 
 | ||||
| New:     5 vert,   1 cntr,     3 tri,   0 strip,   1 fan,     0 ind,   0.052 ms | ||||
| Old:     5 vert,   1 cntr,     3 tri,   0 strip,   0 fan,     3 ind,   0.252 ms | ||||
| New:    19 vert,   1 cntr,    17 tri,   2 strip,   2 fan,     1 ind,   0.911 ms | ||||
| Old:    19 vert,   1 cntr,    17 tri,   0 strip,   0 fan,    17 ind,   0.529 ms | ||||
| New:   151 vert,   1 cntr,   149 tri,  13 strip,  18 fan,     3 ind,    6.82 ms | ||||
| Old:   151 vert,   1 cntr,   149 tri,   0 strip,   3 fan,   143 ind,     2.7 ms | ||||
| New:   574 vert,   1 cntr,   572 tri,  59 strip,  54 fan,    11 ind,    26.6 ms | ||||
| Old:   574 vert,   1 cntr,   572 tri,   0 strip,  31 fan,   499 ind,    12.4 ms | ||||
| 
 | ||||
|   Multiple contours, but no intersections: | ||||
| 
 | ||||
| New:     7 vert,   2 cntr,     7 tri,   1 strip,   0 fan,     0 ind,   0.527 ms | ||||
| Old:     7 vert,   2 cntr,     7 tri,   0 strip,   0 fan,     7 ind,   0.274 ms | ||||
| New:    81 vert,   6 cntr,    89 tri,   9 strip,   7 fan,     6 ind,    3.88 ms | ||||
| Old:    81 vert,   6 cntr,    89 tri,   0 strip,  13 fan,    61 ind,     2.2 ms | ||||
| New:   391 vert,  19 cntr,   413 tri,  37 strip,  32 fan,    26 ind,    20.2 ms | ||||
| Old:   391 vert,  19 cntr,   413 tri,   0 strip,  25 fan,   363 ind,    8.68 ms | ||||
| 
 | ||||
|   Self-intersecting and degenerate examples: | ||||
| 
 | ||||
| Bowtie:  4 vert,   1 cntr,     2 tri,   0 strip,   0 fan,     2 ind,   0.483 ms | ||||
| Star:    5 vert,   1 cntr,     5 tri,   0 strip,   0 fan,     5 ind,    0.91 ms | ||||
| Random: 24 vert,   7 cntr,    46 tri,   2 strip,  12 fan,     7 ind,    5.32 ms | ||||
| Font:  333 vert,   2 cntr,   331 tri,  32 strip,  16 fan,     3 ind,    14.1 ms | ||||
| :      167 vert,  35 cntr,   254 tri,   8 strip,  56 fan,    52 ind,    46.3 ms | ||||
| :       78 vert,   1 cntr,  2675 tri, 148 strip, 207 fan,   180 ind,     243 ms | ||||
| :    12480 vert,   2 cntr, 12478 tri, 736 strip,1275 fan,     5 ind,    1010 ms | ||||
							
								
								
									
										228
									
								
								src/glu-libtess/src/alg-outline
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/glu-libtess/src/alg-outline
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,228 @@ | |||
| /* | ||||
| */ | ||||
| 
 | ||||
| This is only a very brief overview.  There is quite a bit of | ||||
| additional documentation in the source code itself. | ||||
| 
 | ||||
| 
 | ||||
| Goals of robust tesselation | ||||
| --------------------------- | ||||
| 
 | ||||
| The tesselation algorithm is fundamentally a 2D algorithm.  We | ||||
| initially project all data into a plane; our goal is to robustly | ||||
| tesselate the projected data.  The same topological tesselation is | ||||
| then applied to the input data. | ||||
| 
 | ||||
| Topologically, the output should always be a tesselation.  If the | ||||
| input is even slightly non-planar, then some triangles will | ||||
| necessarily be back-facing when viewed from some angles, but the goal | ||||
| is to minimize this effect. | ||||
| 
 | ||||
| The algorithm needs some capability of cleaning up the input data as | ||||
| well as the numerical errors in its own calculations.  One way to do | ||||
| this is to specify a tolerance as defined above, and clean up the | ||||
| input and output during the line sweep process.  At the very least, | ||||
| the algorithm must handle coincident vertices, vertices incident to an | ||||
| edge, and coincident edges. | ||||
| 
 | ||||
| 
 | ||||
| Phases of the algorithm | ||||
| ----------------------- | ||||
| 
 | ||||
| 1. Find the polygon normal N. | ||||
| 2. Project the vertex data onto a plane.  It does not need to be | ||||
|    perpendicular to the normal, eg. we can project onto the plane | ||||
|    perpendicular to the coordinate axis whose dot product with N | ||||
|    is largest. | ||||
| 3. Using a line-sweep algorithm, partition the plane into x-monotone | ||||
|    regions.  Any vertical line intersects an x-monotone region in | ||||
|    at most one interval. | ||||
| 4. Triangulate the x-monotone regions. | ||||
| 5. Group the triangles into strips and fans. | ||||
| 
 | ||||
| 
 | ||||
| Finding the normal vector | ||||
| ------------------------- | ||||
| 
 | ||||
| A common way to find a polygon normal is to compute the signed area | ||||
| when the polygon is projected along the three coordinate axes.  We | ||||
| can't do this, since contours can have zero area without being | ||||
| degenerate (eg. a bowtie). | ||||
| 
 | ||||
| We fit a plane to the vertex data, ignoring how they are connected | ||||
| into contours.  Ideally this would be a least-squares fit; however for | ||||
| our purpose the accuracy of the normal is not important.  Instead we | ||||
| find three vertices which are widely separated, and compute the normal | ||||
| to the triangle they form.  The vertices are chosen so that the | ||||
| triangle has an area at least 1/sqrt(3) times the largest area of any | ||||
| triangle formed using the input vertices.   | ||||
| 
 | ||||
| The contours do affect the orientation of the normal; after computing | ||||
| the normal, we check that the sum of the signed contour areas is | ||||
| non-negative, and reverse the normal if necessary. | ||||
| 
 | ||||
| 
 | ||||
| Projecting the vertices | ||||
| ----------------------- | ||||
| 
 | ||||
| We project the vertices onto a plane perpendicular to one of the three | ||||
| coordinate axes.  This helps numerical accuracy by removing a | ||||
| transformation step between the original input data and the data | ||||
| processed by the algorithm.  The projection also compresses the input | ||||
| data; the 2D distance between vertices after projection may be smaller | ||||
| than the original 2D distance.  However by choosing the coordinate | ||||
| axis whose dot product with the normal is greatest, the compression | ||||
| factor is at most 1/sqrt(3). | ||||
| 
 | ||||
| Even though the *accuracy* of the normal is not that important (since | ||||
| we are projecting perpendicular to a coordinate axis anyway), the | ||||
| *robustness* of the computation is important.  For example, if there | ||||
| are many vertices which lie almost along a line, and one vertex V | ||||
| which is well-separated from the line, then our normal computation | ||||
| should involve V otherwise the results will be garbage. | ||||
| 
 | ||||
| The advantage of projecting perpendicular to the polygon normal is | ||||
| that computed intersection points will be as close as possible to | ||||
| their ideal locations.  To get this behavior, define TRUE_PROJECT. | ||||
| 
 | ||||
| 
 | ||||
| The Line Sweep | ||||
| -------------- | ||||
| 
 | ||||
| There are three data structures: the mesh, the event queue, and the | ||||
| edge dictionary. | ||||
| 
 | ||||
| The mesh is a "quad-edge" data structure which records the topology of | ||||
| the current decomposition; for details see the include file "mesh.h". | ||||
| 
 | ||||
| The event queue simply holds all vertices (both original and computed | ||||
| ones), organized so that we can quickly extract the vertex with the | ||||
| minimum x-coord (and among those, the one with the minimum y-coord). | ||||
| 
 | ||||
| The edge dictionary describes the current intersection of the sweep | ||||
| line with the regions of the polygon.  This is just an ordering of the | ||||
| edges which intersect the sweep line, sorted by their current order of | ||||
| intersection.  For each pair of edges, we store some information about | ||||
| the monotone region between them -- these are call "active regions" | ||||
| (since they are crossed by the current sweep line). | ||||
| 
 | ||||
| The basic algorithm is to sweep from left to right, processing each | ||||
| vertex.  The processed portion of the mesh (left of the sweep line) is | ||||
| a planar decomposition.  As we cross each vertex, we update the mesh | ||||
| and the edge dictionary, then we check any newly adjacent pairs of | ||||
| edges to see if they intersect. | ||||
| 
 | ||||
| A vertex can have any number of edges.  Vertices with many edges can | ||||
| be created as vertices are merged and intersection points are | ||||
| computed.  For unprocessed vertices (right of the sweep line), these | ||||
| edges are in no particular order around the vertex; for processed | ||||
| vertices, the topological ordering should match the geometric ordering. | ||||
| 
 | ||||
| The vertex processing happens in two phases: first we process are the | ||||
| left-going edges (all these edges are currently in the edge | ||||
| dictionary).  This involves: | ||||
| 
 | ||||
|  - deleting the left-going edges from the dictionary; | ||||
|  - relinking the mesh if necessary, so that the order of these edges around | ||||
|    the event vertex matches the order in the dictionary; | ||||
|  - marking any terminated regions (regions which lie between two left-going | ||||
|    edges) as either "inside" or "outside" according to their winding number. | ||||
| 
 | ||||
| When there are no left-going edges, and the event vertex is in an | ||||
| "interior" region, we need to add an edge (to split the region into | ||||
| monotone pieces).  To do this we simply join the event vertex to the | ||||
| rightmost left endpoint of the upper or lower edge of the containing | ||||
| region. | ||||
| 
 | ||||
| Then we process the right-going edges.  This involves: | ||||
| 
 | ||||
|  - inserting the edges in the edge dictionary; | ||||
|  - computing the winding number of any newly created active regions. | ||||
|    We can compute this incrementally using the winding of each edge | ||||
|    that we cross as we walk through the dictionary. | ||||
|  - relinking the mesh if necessary, so that the order of these edges around | ||||
|    the event vertex matches the order in the dictionary; | ||||
|  - checking any newly adjacent edges for intersection and/or merging. | ||||
| 
 | ||||
| If there are no right-going edges, again we need to add one to split | ||||
| the containing region into monotone pieces.  In our case it is most | ||||
| convenient to add an edge to the leftmost right endpoint of either | ||||
| containing edge; however we may need to change this later (see the | ||||
| code for details). | ||||
| 
 | ||||
| 
 | ||||
| Invariants | ||||
| ---------- | ||||
| 
 | ||||
| These are the most important invariants maintained during the sweep. | ||||
| We define a function VertLeq(v1,v2) which defines the order in which | ||||
| vertices cross the sweep line, and a function EdgeLeq(e1,e2; loc) | ||||
| which says whether e1 is below e2 at the sweep event location "loc". | ||||
| This function is defined only at sweep event locations which lie | ||||
| between the rightmost left endpoint of {e1,e2}, and the leftmost right | ||||
| endpoint of {e1,e2}. | ||||
| 
 | ||||
| Invariants for the Edge Dictionary. | ||||
| 
 | ||||
|  - Each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) | ||||
|    at any valid location of the sweep event. | ||||
|  - If EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 | ||||
|    share a common endpoint. | ||||
|  - For each e in the dictionary, e->Dst has been processed but not e->Org. | ||||
|  - Each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) | ||||
|    where "event" is the current sweep line event. | ||||
|  - No edge e has zero length. | ||||
|  - No two edges have identical left and right endpoints. | ||||
|   | ||||
| Invariants for the Mesh (the processed portion). | ||||
| 
 | ||||
|  - The portion of the mesh left of the sweep line is a planar graph, | ||||
|    ie. there is *some* way to embed it in the plane. | ||||
|  - No processed edge has zero length. | ||||
|  - No two processed vertices have identical coordinates. | ||||
|  - Each "inside" region is monotone, ie. can be broken into two chains | ||||
|    of monotonically increasing vertices according to VertLeq(v1,v2) | ||||
|    - a non-invariant: these chains may intersect (slightly) due to | ||||
|      numerical errors, but this does not affect the algorithm's operation. | ||||
| 
 | ||||
| Invariants for the Sweep. | ||||
| 
 | ||||
|  - If a vertex has any left-going edges, then these must be in the edge | ||||
|    dictionary at the time the vertex is processed. | ||||
|  - If an edge is marked "fixUpperEdge" (it is a temporary edge introduced | ||||
|    by ConnectRightVertex), then it is the only right-going edge from | ||||
|    its associated vertex.  (This says that these edges exist only | ||||
|    when it is necessary.) | ||||
| 
 | ||||
| 
 | ||||
| Robustness | ||||
| ---------- | ||||
| 
 | ||||
| The key to the robustness of the algorithm is maintaining the | ||||
| invariants above, especially the correct ordering of the edge | ||||
| dictionary.  We achieve this by: | ||||
| 
 | ||||
|   1. Writing the numerical computations for maximum precision rather | ||||
|      than maximum speed. | ||||
|       | ||||
|   2. Making no assumptions at all about the results of the edge | ||||
|      intersection calculations -- for sufficiently degenerate inputs, | ||||
|      the computed location is not much better than a random number. | ||||
|       | ||||
|   3. When numerical errors violate the invariants, restore them | ||||
|      by making *topological* changes when necessary (ie. relinking | ||||
|      the mesh structure). | ||||
|       | ||||
|       | ||||
| Triangulation and Grouping | ||||
| -------------------------- | ||||
| 
 | ||||
| We finish the line sweep before doing any triangulation.  This is | ||||
| because even after a monotone region is complete, there can be further | ||||
| changes to its vertex data because of further vertex merging. | ||||
| 
 | ||||
| After triangulating all monotone regions, we want to group the | ||||
| triangles into fans and strips.  We do this using a greedy approach. | ||||
| The triangulation itself is not optimized to reduce the number of | ||||
| primitives; we just try to get a reasonable decomposition of the | ||||
| computed triangulation. | ||||
							
								
								
									
										100
									
								
								src/glu-libtess/src/dict-list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/glu-libtess/src/dict-list.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __dict_list_h_ | ||||
| #define __dict_list_h_ | ||||
| 
 | ||||
| /* Use #define's so that another heap implementation can use this one */ | ||||
| 
 | ||||
| #define DictKey		DictListKey | ||||
| #define Dict		DictList | ||||
| #define DictNode	DictListNode | ||||
| 
 | ||||
| #define dictNewDict(frame,leq)		__gl_dictListNewDict(frame,leq) | ||||
| #define dictDeleteDict(dict)		__gl_dictListDeleteDict(dict) | ||||
| 
 | ||||
| #define dictSearch(dict,key)		__gl_dictListSearch(dict,key) | ||||
| #define dictInsert(dict,key)		__gl_dictListInsert(dict,key) | ||||
| #define dictInsertBefore(dict,node,key)	__gl_dictListInsertBefore(dict,node,key) | ||||
| #define dictDelete(dict,node)		__gl_dictListDelete(dict,node) | ||||
| 
 | ||||
| #define dictKey(n)			__gl_dictListKey(n) | ||||
| #define dictSucc(n)			__gl_dictListSucc(n) | ||||
| #define dictPred(n)			__gl_dictListPred(n) | ||||
| #define dictMin(d)			__gl_dictListMin(d) | ||||
| #define dictMax(d)			__gl_dictListMax(d) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| typedef void *DictKey; | ||||
| typedef struct Dict Dict; | ||||
| typedef struct DictNode DictNode; | ||||
| 
 | ||||
| Dict		*dictNewDict( | ||||
| 			void *frame, | ||||
| 			int (*leq)(void *frame, DictKey key1, DictKey key2) ); | ||||
| 			 | ||||
| void		dictDeleteDict( Dict *dict ); | ||||
| 
 | ||||
| /* Search returns the node with the smallest key greater than or equal
 | ||||
|  * to the given key.  If there is no such key, returns a node whose | ||||
|  * key is NULL.  Similarly, Succ(Max(d)) has a NULL key, etc. | ||||
|  */ | ||||
| DictNode	*dictSearch( Dict *dict, DictKey key ); | ||||
| DictNode	*dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); | ||||
| void		dictDelete( Dict *dict, DictNode *node ); | ||||
| 
 | ||||
| #define		__gl_dictListKey(n)	((n)->key) | ||||
| #define		__gl_dictListSucc(n)	((n)->next) | ||||
| #define		__gl_dictListPred(n)	((n)->prev) | ||||
| #define		__gl_dictListMin(d)	((d)->head.next) | ||||
| #define		__gl_dictListMax(d)	((d)->head.prev) | ||||
| #define	       __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) | ||||
| 
 | ||||
| 
 | ||||
| /*** Private data structures ***/ | ||||
| 
 | ||||
| struct DictNode { | ||||
|   DictKey	key; | ||||
|   DictNode	*next; | ||||
|   DictNode	*prev; | ||||
| }; | ||||
| 
 | ||||
| struct Dict { | ||||
|   DictNode	head; | ||||
|   void		*frame; | ||||
|   int		(*leq)(void *frame, DictKey key1, DictKey key2); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										111
									
								
								src/glu-libtess/src/dict.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/glu-libtess/src/dict.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,111 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include "dict-list.h" | ||||
| #include "memalloc.h" | ||||
| 
 | ||||
| /* really __gl_dictListNewDict */ | ||||
| Dict *dictNewDict( void *frame, | ||||
| 		   int (*leq)(void *frame, DictKey key1, DictKey key2) ) | ||||
| { | ||||
|   Dict *dict = (Dict *) memAlloc( sizeof( Dict )); | ||||
|   DictNode *head; | ||||
| 
 | ||||
|   if (dict == NULL) return NULL; | ||||
| 
 | ||||
|   head = &dict->head; | ||||
| 
 | ||||
|   head->key = NULL; | ||||
|   head->next = head; | ||||
|   head->prev = head; | ||||
| 
 | ||||
|   dict->frame = frame; | ||||
|   dict->leq = leq; | ||||
| 
 | ||||
|   return dict; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_dictListDeleteDict */ | ||||
| void dictDeleteDict( Dict *dict ) | ||||
| { | ||||
|   DictNode *node, *next; | ||||
| 
 | ||||
|   for( node = dict->head.next; node != &dict->head; node = next ) { | ||||
|     next = node->next; | ||||
|     memFree( node ); | ||||
|   } | ||||
|   memFree( dict ); | ||||
| } | ||||
| 
 | ||||
| /* really __gl_dictListInsertBefore */ | ||||
| DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) | ||||
| { | ||||
|   DictNode *newNode; | ||||
| 
 | ||||
|   do { | ||||
|     node = node->prev; | ||||
|   } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); | ||||
| 
 | ||||
|   newNode = (DictNode *) memAlloc( sizeof( DictNode )); | ||||
|   if (newNode == NULL) return NULL; | ||||
| 
 | ||||
|   newNode->key = key; | ||||
|   newNode->next = node->next; | ||||
|   node->next->prev = newNode; | ||||
|   newNode->prev = node; | ||||
|   node->next = newNode; | ||||
| 
 | ||||
|   return newNode; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_dictListDelete */ | ||||
| void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ | ||||
| { | ||||
|   node->next->prev = node->prev; | ||||
|   node->prev->next = node->next; | ||||
|   memFree( node ); | ||||
| } | ||||
| 
 | ||||
| /* really __gl_dictListSearch */ | ||||
| DictNode *dictSearch( Dict *dict, DictKey key ) | ||||
| { | ||||
|   DictNode *node = &dict->head; | ||||
| 
 | ||||
|   do { | ||||
|     node = node->next; | ||||
|   } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
							
								
								
									
										100
									
								
								src/glu-libtess/src/dict.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/glu-libtess/src/dict.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __dict_list_h_ | ||||
| #define __dict_list_h_ | ||||
| 
 | ||||
| /* Use #define's so that another heap implementation can use this one */ | ||||
| 
 | ||||
| #define DictKey		DictListKey | ||||
| #define Dict		DictList | ||||
| #define DictNode	DictListNode | ||||
| 
 | ||||
| #define dictNewDict(frame,leq)		__gl_dictListNewDict(frame,leq) | ||||
| #define dictDeleteDict(dict)		__gl_dictListDeleteDict(dict) | ||||
| 
 | ||||
| #define dictSearch(dict,key)		__gl_dictListSearch(dict,key) | ||||
| #define dictInsert(dict,key)		__gl_dictListInsert(dict,key) | ||||
| #define dictInsertBefore(dict,node,key)	__gl_dictListInsertBefore(dict,node,key) | ||||
| #define dictDelete(dict,node)		__gl_dictListDelete(dict,node) | ||||
| 
 | ||||
| #define dictKey(n)			__gl_dictListKey(n) | ||||
| #define dictSucc(n)			__gl_dictListSucc(n) | ||||
| #define dictPred(n)			__gl_dictListPred(n) | ||||
| #define dictMin(d)			__gl_dictListMin(d) | ||||
| #define dictMax(d)			__gl_dictListMax(d) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| typedef void *DictKey; | ||||
| typedef struct Dict Dict; | ||||
| typedef struct DictNode DictNode; | ||||
| 
 | ||||
| Dict		*dictNewDict( | ||||
| 			void *frame, | ||||
| 			int (*leq)(void *frame, DictKey key1, DictKey key2) ); | ||||
| 			 | ||||
| void		dictDeleteDict( Dict *dict ); | ||||
| 
 | ||||
| /* Search returns the node with the smallest key greater than or equal
 | ||||
|  * to the given key.  If there is no such key, returns a node whose | ||||
|  * key is NULL.  Similarly, Succ(Max(d)) has a NULL key, etc. | ||||
|  */ | ||||
| DictNode	*dictSearch( Dict *dict, DictKey key ); | ||||
| DictNode	*dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); | ||||
| void		dictDelete( Dict *dict, DictNode *node ); | ||||
| 
 | ||||
| #define		__gl_dictListKey(n)	((n)->key) | ||||
| #define		__gl_dictListSucc(n)	((n)->next) | ||||
| #define		__gl_dictListPred(n)	((n)->prev) | ||||
| #define		__gl_dictListMin(d)	((d)->head.next) | ||||
| #define		__gl_dictListMax(d)	((d)->head.prev) | ||||
| #define	       __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) | ||||
| 
 | ||||
| 
 | ||||
| /*** Private data structures ***/ | ||||
| 
 | ||||
| struct DictNode { | ||||
|   DictKey	key; | ||||
|   DictNode	*next; | ||||
|   DictNode	*prev; | ||||
| }; | ||||
| 
 | ||||
| struct Dict { | ||||
|   DictNode	head; | ||||
|   void		*frame; | ||||
|   int		(*leq)(void *frame, DictKey key1, DictKey key2); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										264
									
								
								src/glu-libtess/src/geom.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								src/glu-libtess/src/geom.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,264 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <assert.h> | ||||
| #include "mesh.h" | ||||
| #include "geom.h" | ||||
| 
 | ||||
| int __gl_vertLeq( GLUvertex *u, GLUvertex *v ) | ||||
| { | ||||
|   /* Returns TRUE if u is lexicographically <= v. */ | ||||
| 
 | ||||
|   return VertLeq( u, v ); | ||||
| } | ||||
| 
 | ||||
| GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) | ||||
| { | ||||
|   /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
 | ||||
|    * evaluates the t-coord of the edge uw at the s-coord of the vertex v. | ||||
|    * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. | ||||
|    * If uw is vertical (and thus passes thru v), the result is zero. | ||||
|    * | ||||
|    * The calculation is extremely accurate and stable, even when v | ||||
|    * is very close to u or w.  In particular if we set v->t = 0 and | ||||
|    * let r be the negated result (this evaluates (uw)(v->s)), then | ||||
|    * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). | ||||
|    */ | ||||
|   GLdouble gapL, gapR; | ||||
| 
 | ||||
|   assert( VertLeq( u, v ) && VertLeq( v, w )); | ||||
|    | ||||
|   gapL = v->s - u->s; | ||||
|   gapR = w->s - v->s; | ||||
| 
 | ||||
|   if( gapL + gapR > 0 ) { | ||||
|     if( gapL < gapR ) { | ||||
|       return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); | ||||
|     } else { | ||||
|       return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); | ||||
|     } | ||||
|   } | ||||
|   /* vertical line */ | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) | ||||
| { | ||||
|   /* Returns a number whose sign matches EdgeEval(u,v,w) but which
 | ||||
|    * is cheaper to evaluate.  Returns > 0, == 0 , or < 0 | ||||
|    * as v is above, on, or below the edge uw. | ||||
|    */ | ||||
|   GLdouble gapL, gapR; | ||||
| 
 | ||||
|   assert( VertLeq( u, v ) && VertLeq( v, w )); | ||||
|    | ||||
|   gapL = v->s - u->s; | ||||
|   gapR = w->s - v->s; | ||||
| 
 | ||||
|   if( gapL + gapR > 0 ) { | ||||
|     return (v->t - w->t) * gapL + (v->t - u->t) * gapR; | ||||
|   } | ||||
|   /* vertical line */ | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /***********************************************************************
 | ||||
|  * Define versions of EdgeSign, EdgeEval with s and t transposed. | ||||
|  */ | ||||
| 
 | ||||
| GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) | ||||
| { | ||||
|   /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
 | ||||
|    * evaluates the t-coord of the edge uw at the s-coord of the vertex v. | ||||
|    * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. | ||||
|    * If uw is vertical (and thus passes thru v), the result is zero. | ||||
|    * | ||||
|    * The calculation is extremely accurate and stable, even when v | ||||
|    * is very close to u or w.  In particular if we set v->s = 0 and | ||||
|    * let r be the negated result (this evaluates (uw)(v->t)), then | ||||
|    * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). | ||||
|    */ | ||||
|   GLdouble gapL, gapR; | ||||
| 
 | ||||
|   assert( TransLeq( u, v ) && TransLeq( v, w )); | ||||
|    | ||||
|   gapL = v->t - u->t; | ||||
|   gapR = w->t - v->t; | ||||
| 
 | ||||
|   if( gapL + gapR > 0 ) { | ||||
|     if( gapL < gapR ) { | ||||
|       return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); | ||||
|     } else { | ||||
|       return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); | ||||
|     } | ||||
|   } | ||||
|   /* vertical line */ | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) | ||||
| { | ||||
|   /* Returns a number whose sign matches TransEval(u,v,w) but which
 | ||||
|    * is cheaper to evaluate.  Returns > 0, == 0 , or < 0 | ||||
|    * as v is above, on, or below the edge uw. | ||||
|    */ | ||||
|   GLdouble gapL, gapR; | ||||
| 
 | ||||
|   assert( TransLeq( u, v ) && TransLeq( v, w )); | ||||
|    | ||||
|   gapL = v->t - u->t; | ||||
|   gapR = w->t - v->t; | ||||
| 
 | ||||
|   if( gapL + gapR > 0 ) { | ||||
|     return (v->s - w->s) * gapL + (v->s - u->s) * gapR; | ||||
|   } | ||||
|   /* vertical line */ | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ) | ||||
| { | ||||
|   /* For almost-degenerate situations, the results are not reliable.
 | ||||
|    * Unless the floating-point arithmetic can be performed without | ||||
|    * rounding errors, *any* implementation will give incorrect results | ||||
|    * on some degenerate inputs, so the client must have some way to | ||||
|    * handle this situation. | ||||
|    */ | ||||
|   return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; | ||||
| } | ||||
| 
 | ||||
| /* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
 | ||||
|  * or (x+y)/2 if a==b==0.  It requires that a,b >= 0, and enforces | ||||
|  * this in the rare case that one argument is slightly negative. | ||||
|  * The implementation is extremely stable numerically. | ||||
|  * In particular it guarantees that the result r satisfies | ||||
|  * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate | ||||
|  * even when a and b differ greatly in magnitude. | ||||
|  */ | ||||
| #define RealInterpolate(a,x,b,y)			\ | ||||
|   (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b,		\ | ||||
|   ((a <= b) ? ((b == 0) ? ((x+y) / 2)			\ | ||||
|                         : (x + (y-x) * (a/(a+b))))	\ | ||||
|             : (y + (x-y) * (b/(a+b))))) | ||||
| 
 | ||||
| #ifndef FOR_TRITE_TEST_PROGRAM | ||||
| #define Interpolate(a,x,b,y)	RealInterpolate(a,x,b,y) | ||||
| #else | ||||
| 
 | ||||
| /* Claim: the ONLY property the sweep algorithm relies on is that
 | ||||
|  * MIN(x,y) <= r <= MAX(x,y).  This is a nasty way to test that. | ||||
|  */ | ||||
| #include <stdlib.h> | ||||
| extern int RandomInterpolate; | ||||
| 
 | ||||
| GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y) | ||||
| { | ||||
| printf("*********************%d\n",RandomInterpolate); | ||||
|   if( RandomInterpolate ) { | ||||
|     a = 1.2 * drand48() - 0.1; | ||||
|     a = (a < 0) ? 0 : ((a > 1) ? 1 : a); | ||||
|     b = 1.0 - a; | ||||
|   } | ||||
|   return RealInterpolate(a,x,b,y); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #define Swap(a,b)	do { GLUvertex *t = a; a = b; b = t; } while (0) | ||||
| 
 | ||||
| void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, | ||||
| 			 GLUvertex *o2, GLUvertex *d2, | ||||
| 			 GLUvertex *v ) | ||||
| /* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
 | ||||
|  * The computed point is guaranteed to lie in the intersection of the | ||||
|  * bounding rectangles defined by each edge. | ||||
|  */ | ||||
| { | ||||
|   GLdouble z1, z2; | ||||
| 
 | ||||
|   /* This is certainly not the most efficient way to find the intersection
 | ||||
|    * of two line segments, but it is very numerically stable. | ||||
|    * | ||||
|    * Strategy: find the two middle vertices in the VertLeq ordering, | ||||
|    * and interpolate the intersection s-value from these.  Then repeat | ||||
|    * using the TransLeq ordering to find the intersection t-value. | ||||
|    */ | ||||
| 
 | ||||
|   if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } | ||||
|   if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } | ||||
|   if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } | ||||
| 
 | ||||
|   if( ! VertLeq( o2, d1 )) { | ||||
|     /* Technically, no intersection -- do our best */ | ||||
|     v->s = (o2->s + d1->s) / 2; | ||||
|   } else if( VertLeq( d1, d2 )) { | ||||
|     /* Interpolate between o2 and d1 */ | ||||
|     z1 = EdgeEval( o1, o2, d1 ); | ||||
|     z2 = EdgeEval( o2, d1, d2 ); | ||||
|     if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } | ||||
|     v->s = Interpolate( z1, o2->s, z2, d1->s ); | ||||
|   } else { | ||||
|     /* Interpolate between o2 and d2 */ | ||||
|     z1 = EdgeSign( o1, o2, d1 ); | ||||
|     z2 = -EdgeSign( o1, d2, d1 ); | ||||
|     if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } | ||||
|     v->s = Interpolate( z1, o2->s, z2, d2->s ); | ||||
|   } | ||||
| 
 | ||||
|   /* Now repeat the process for t */ | ||||
| 
 | ||||
|   if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } | ||||
|   if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } | ||||
|   if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } | ||||
| 
 | ||||
|   if( ! TransLeq( o2, d1 )) { | ||||
|     /* Technically, no intersection -- do our best */ | ||||
|     v->t = (o2->t + d1->t) / 2; | ||||
|   } else if( TransLeq( d1, d2 )) { | ||||
|     /* Interpolate between o2 and d1 */ | ||||
|     z1 = TransEval( o1, o2, d1 ); | ||||
|     z2 = TransEval( o2, d1, d2 ); | ||||
|     if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } | ||||
|     v->t = Interpolate( z1, o2->t, z2, d1->t ); | ||||
|   } else { | ||||
|     /* Interpolate between o2 and d2 */ | ||||
|     z1 = TransSign( o1, o2, d1 ); | ||||
|     z2 = -TransSign( o1, d2, d1 ); | ||||
|     if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } | ||||
|     v->t = Interpolate( z1, o2->t, z2, d2->t ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										84
									
								
								src/glu-libtess/src/geom.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/glu-libtess/src/geom.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,84 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __geom_h_ | ||||
| #define __geom_h_ | ||||
| 
 | ||||
| #include "mesh.h" | ||||
| 
 | ||||
| #ifdef NO_BRANCH_CONDITIONS | ||||
| /* MIPS architecture has special instructions to evaluate boolean
 | ||||
|  * conditions -- more efficient than branching, IF you can get the | ||||
|  * compiler to generate the right instructions (SGI compiler doesn't) | ||||
|  */ | ||||
| #define VertEq(u,v)	(((u)->s == (v)->s) & ((u)->t == (v)->t)) | ||||
| #define VertLeq(u,v)	(((u)->s < (v)->s) | \ | ||||
|                          ((u)->s == (v)->s & (u)->t <= (v)->t)) | ||||
| #else | ||||
| #define VertEq(u,v)	((u)->s == (v)->s && (u)->t == (v)->t) | ||||
| #define VertLeq(u,v)	(((u)->s < (v)->s) || \ | ||||
|                          ((u)->s == (v)->s && (u)->t <= (v)->t)) | ||||
| #endif | ||||
| 
 | ||||
| #define EdgeEval(u,v,w) __gl_edgeEval(u,v,w) | ||||
| #define EdgeSign(u,v,w) __gl_edgeSign(u,v,w) | ||||
| 
 | ||||
| /* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ | ||||
| 
 | ||||
| #define TransLeq(u,v)	(((u)->t < (v)->t) || \ | ||||
|                          ((u)->t == (v)->t && (u)->s <= (v)->s)) | ||||
| #define TransEval(u,v,w)	__gl_transEval(u,v,w) | ||||
| #define TransSign(u,v,w)	__gl_transSign(u,v,w) | ||||
| 
 | ||||
| 
 | ||||
| #define EdgeGoesLeft(e) 	VertLeq( (e)->Dst, (e)->Org ) | ||||
| #define EdgeGoesRight(e)	VertLeq( (e)->Org, (e)->Dst ) | ||||
| 
 | ||||
| #undef	ABS | ||||
| #define ABS(x)	((x) < 0 ? -(x) : (x)) | ||||
| #define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) | ||||
| 
 | ||||
| #define VertCCW(u,v,w)	__gl_vertCCW(u,v,w) | ||||
| 
 | ||||
| int		__gl_vertLeq( GLUvertex *u, GLUvertex *v ); | ||||
| GLdouble	__gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); | ||||
| GLdouble	__gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); | ||||
| GLdouble	__gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); | ||||
| GLdouble	__gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); | ||||
| int		__gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ); | ||||
| void		__gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, | ||||
| 				    GLUvertex *o2, GLUvertex *d2, | ||||
| 				    GLUvertex *v ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										86
									
								
								src/glu-libtess/src/gluos.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/glu-libtess/src/gluos.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| /*
 | ||||
| ** gluos.h - operating system dependencies for GLU | ||||
| ** | ||||
| */ | ||||
| #ifdef __VMS | ||||
| #ifdef __cplusplus | ||||
| #pragma message disable nocordel | ||||
| #pragma message disable codeunreachable | ||||
| #pragma message disable codcauunr | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __WATCOMC__ | ||||
| /* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the
 | ||||
|  * code at the moment, as it is pretty ugly. | ||||
|  */ | ||||
| #pragma warning 7   10 | ||||
| #pragma warning 13  10 | ||||
| #pragma warning 14  10 | ||||
| #pragma warning 367 10 | ||||
| #pragma warning 379 10 | ||||
| #pragma warning 726 10 | ||||
| #pragma warning 836 10 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef BUILD_FOR_SNAP | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <malloc.h> | ||||
| 
 | ||||
| #elif defined(_WIN32) | ||||
| 
 | ||||
| #include <stdlib.h>	    /* For _MAX_PATH definition */ | ||||
| #include <stdio.h> | ||||
| #include <malloc.h> | ||||
| 
 | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| #define NOGDI | ||||
| #define NOIME | ||||
| #define NOMINMAX | ||||
| 
 | ||||
| #ifdef __MINGW64_VERSION_MAJOR | ||||
|   #undef _WIN32_WINNT | ||||
| #endif | ||||
| 
 | ||||
| #ifndef _WIN32_WINNT | ||||
|   /* XXX: Workaround a bug in mingw-w64's headers when NOGDI is set and
 | ||||
|    * _WIN32_WINNT >= 0x0600 */ | ||||
|   #define _WIN32_WINNT 0x0400 | ||||
| #endif | ||||
| #ifndef STRICT | ||||
|   #define STRICT 1 | ||||
| #endif | ||||
| 
 | ||||
| #include <windows.h> | ||||
| 
 | ||||
| /* Disable warnings */ | ||||
| #if defined(_MSC_VER) | ||||
| #pragma warning(disable : 4101) | ||||
| #pragma warning(disable : 4244) | ||||
| #pragma warning(disable : 4761) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300 | ||||
| #pragma comment(linker, "/OPT:NOWIN98") | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WINGDIAPI | ||||
| #define WINGDIAPI | ||||
| #endif | ||||
| 
 | ||||
| #elif defined(__OS2__) | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <malloc.h> | ||||
| #define WINGDIAPI | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| /* Disable Microsoft-specific keywords */ | ||||
| #define GLAPIENTRY | ||||
| #define WINGDIAPI | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										55
									
								
								src/glu-libtess/src/memalloc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/glu-libtess/src/memalloc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "memalloc.h" | ||||
| #include "string.h" | ||||
| 
 | ||||
| int __gl_memInit( size_t maxFast ) | ||||
| { | ||||
| #ifndef NO_MALLOPT | ||||
| /*  mallopt( M_MXFAST, maxFast );*/ | ||||
| #ifdef MEMORY_DEBUG | ||||
|   mallopt( M_DEBUG, 1 ); | ||||
| #endif | ||||
| #endif | ||||
|    return 1; | ||||
| } | ||||
| 
 | ||||
| #ifdef MEMORY_DEBUG | ||||
| void *__gl_memAlloc( size_t n ) | ||||
| { | ||||
|   return memset( malloc( n ), 0xa5, n ); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										54
									
								
								src/glu-libtess/src/memalloc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/glu-libtess/src/memalloc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __memalloc_simple_h_ | ||||
| #define __memalloc_simple_h_ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #define memRealloc	realloc | ||||
| #define memFree		free | ||||
| 
 | ||||
| #define memInit		__gl_memInit | ||||
| /*extern void		__gl_memInit( size_t );*/ | ||||
| extern int		__gl_memInit( size_t ); | ||||
| 
 | ||||
| #ifndef MEMORY_DEBUG | ||||
| #define memAlloc	malloc | ||||
| #else | ||||
| #define memAlloc	__gl_memAlloc | ||||
| extern void *		__gl_memAlloc( size_t ); | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										798
									
								
								src/glu-libtess/src/mesh.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										798
									
								
								src/glu-libtess/src/mesh.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,798 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| #include "mesh.h" | ||||
| #include "memalloc.h" | ||||
| 
 | ||||
| #ifndef TRUE | ||||
| #define TRUE 1 | ||||
| #endif | ||||
| #ifndef FALSE | ||||
| #define FALSE 0 | ||||
| #endif | ||||
| 
 | ||||
| static GLUvertex *allocVertex() | ||||
| { | ||||
|    return (GLUvertex *)memAlloc( sizeof( GLUvertex )); | ||||
| } | ||||
| 
 | ||||
| static GLUface *allocFace() | ||||
| { | ||||
|    return (GLUface *)memAlloc( sizeof( GLUface )); | ||||
| } | ||||
| 
 | ||||
| /************************ Utility Routines ************************/ | ||||
| 
 | ||||
| /* Allocate and free half-edges in pairs for efficiency.
 | ||||
|  * The *only* place that should use this fact is allocation/free. | ||||
|  */ | ||||
| typedef struct { GLUhalfEdge e, eSym; } EdgePair; | ||||
| 
 | ||||
| /* MakeEdge creates a new pair of half-edges which form their own loop.
 | ||||
|  * No vertex or face structures are allocated, but these must be assigned | ||||
|  * before the current edge operation is completed. | ||||
|  */ | ||||
| static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext ) | ||||
| { | ||||
|   GLUhalfEdge *e; | ||||
|   GLUhalfEdge *eSym; | ||||
|   GLUhalfEdge *ePrev; | ||||
|   EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair )); | ||||
|   if (pair == NULL) return NULL; | ||||
| 
 | ||||
|   e = &pair->e; | ||||
|   eSym = &pair->eSym; | ||||
| 
 | ||||
|   /* Make sure eNext points to the first edge of the edge pair */ | ||||
|   if( eNext->Sym < eNext ) { eNext = eNext->Sym; } | ||||
| 
 | ||||
|   /* Insert in circular doubly-linked list before eNext.
 | ||||
|    * Note that the prev pointer is stored in Sym->next. | ||||
|    */ | ||||
|   ePrev = eNext->Sym->next; | ||||
|   eSym->next = ePrev; | ||||
|   ePrev->Sym->next = e; | ||||
|   e->next = eNext; | ||||
|   eNext->Sym->next = eSym; | ||||
| 
 | ||||
|   e->Sym = eSym; | ||||
|   e->Onext = e; | ||||
|   e->Lnext = eSym; | ||||
|   e->Org = NULL; | ||||
|   e->Lface = NULL; | ||||
|   e->winding = 0; | ||||
|   e->activeRegion = NULL; | ||||
| 
 | ||||
|   eSym->Sym = e; | ||||
|   eSym->Onext = eSym; | ||||
|   eSym->Lnext = e; | ||||
|   eSym->Org = NULL; | ||||
|   eSym->Lface = NULL; | ||||
|   eSym->winding = 0; | ||||
|   eSym->activeRegion = NULL; | ||||
| 
 | ||||
|   return e; | ||||
| } | ||||
| 
 | ||||
| /* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
 | ||||
|  * CS348a notes (see mesh.h).  Basically it modifies the mesh so that | ||||
|  * a->Onext and b->Onext are exchanged.  This can have various effects | ||||
|  * depending on whether a and b belong to different face or vertex rings. | ||||
|  * For more explanation see __gl_meshSplice() below. | ||||
|  */ | ||||
| static void Splice( GLUhalfEdge *a, GLUhalfEdge *b ) | ||||
| { | ||||
|   GLUhalfEdge *aOnext = a->Onext; | ||||
|   GLUhalfEdge *bOnext = b->Onext; | ||||
| 
 | ||||
|   aOnext->Sym->Lnext = b; | ||||
|   bOnext->Sym->Lnext = a; | ||||
|   a->Onext = bOnext; | ||||
|   b->Onext = aOnext; | ||||
| } | ||||
| 
 | ||||
| /* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
 | ||||
|  * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives | ||||
|  * a place to insert the new vertex in the global vertex list.  We insert | ||||
|  * the new vertex *before* vNext so that algorithms which walk the vertex | ||||
|  * list will not see the newly created vertices. | ||||
|  */ | ||||
| static void MakeVertex( GLUvertex *newVertex,  | ||||
| 			GLUhalfEdge *eOrig, GLUvertex *vNext ) | ||||
| { | ||||
|   GLUhalfEdge *e; | ||||
|   GLUvertex *vPrev; | ||||
|   GLUvertex *vNew = newVertex; | ||||
| 
 | ||||
|   assert(vNew != NULL); | ||||
| 
 | ||||
|   /* insert in circular doubly-linked list before vNext */ | ||||
|   vPrev = vNext->prev; | ||||
|   vNew->prev = vPrev; | ||||
|   vPrev->next = vNew; | ||||
|   vNew->next = vNext; | ||||
|   vNext->prev = vNew; | ||||
| 
 | ||||
|   vNew->anEdge = eOrig; | ||||
|   vNew->data = NULL; | ||||
|   /* leave coords, s, t undefined */ | ||||
| 
 | ||||
|   /* fix other edges on this vertex loop */ | ||||
|   e = eOrig; | ||||
|   do { | ||||
|     e->Org = vNew; | ||||
|     e = e->Onext; | ||||
|   } while( e != eOrig ); | ||||
| } | ||||
| 
 | ||||
| /* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
 | ||||
|  * face of all edges in the face loop to which eOrig belongs.  "fNext" gives | ||||
|  * a place to insert the new face in the global face list.  We insert | ||||
|  * the new face *before* fNext so that algorithms which walk the face | ||||
|  * list will not see the newly created faces. | ||||
|  */ | ||||
| static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext ) | ||||
| { | ||||
|   GLUhalfEdge *e; | ||||
|   GLUface *fPrev; | ||||
|   GLUface *fNew = newFace; | ||||
| 
 | ||||
|   assert(fNew != NULL);  | ||||
| 
 | ||||
|   /* insert in circular doubly-linked list before fNext */ | ||||
|   fPrev = fNext->prev; | ||||
|   fNew->prev = fPrev; | ||||
|   fPrev->next = fNew; | ||||
|   fNew->next = fNext; | ||||
|   fNext->prev = fNew; | ||||
| 
 | ||||
|   fNew->anEdge = eOrig; | ||||
|   fNew->data = NULL; | ||||
|   fNew->trail = NULL; | ||||
|   fNew->marked = FALSE; | ||||
| 
 | ||||
|   /* The new face is marked "inside" if the old one was.  This is a
 | ||||
|    * convenience for the common case where a face has been split in two. | ||||
|    */ | ||||
|   fNew->inside = fNext->inside; | ||||
| 
 | ||||
|   /* fix other edges on this face loop */ | ||||
|   e = eOrig; | ||||
|   do { | ||||
|     e->Lface = fNew; | ||||
|     e = e->Lnext; | ||||
|   } while( e != eOrig ); | ||||
| } | ||||
| 
 | ||||
| /* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
 | ||||
|  * and removes from the global edge list. | ||||
|  */ | ||||
| static void KillEdge( GLUhalfEdge *eDel ) | ||||
| { | ||||
|   GLUhalfEdge *ePrev, *eNext; | ||||
| 
 | ||||
|   /* Half-edges are allocated in pairs, see EdgePair above */ | ||||
|   if( eDel->Sym < eDel ) { eDel = eDel->Sym; } | ||||
| 
 | ||||
|   /* delete from circular doubly-linked list */ | ||||
|   eNext = eDel->next; | ||||
|   ePrev = eDel->Sym->next; | ||||
|   eNext->Sym->next = ePrev; | ||||
|   ePrev->Sym->next = eNext; | ||||
| 
 | ||||
|   memFree( eDel ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* KillVertex( vDel ) destroys a vertex and removes it from the global
 | ||||
|  * vertex list.  It updates the vertex loop to point to a given new vertex. | ||||
|  */ | ||||
| static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg ) | ||||
| { | ||||
|   GLUhalfEdge *e, *eStart = vDel->anEdge; | ||||
|   GLUvertex *vPrev, *vNext; | ||||
| 
 | ||||
|   /* change the origin of all affected edges */ | ||||
|   e = eStart; | ||||
|   do { | ||||
|     e->Org = newOrg; | ||||
|     e = e->Onext; | ||||
|   } while( e != eStart ); | ||||
| 
 | ||||
|   /* delete from circular doubly-linked list */ | ||||
|   vPrev = vDel->prev; | ||||
|   vNext = vDel->next; | ||||
|   vNext->prev = vPrev; | ||||
|   vPrev->next = vNext; | ||||
| 
 | ||||
|   memFree( vDel ); | ||||
| } | ||||
| 
 | ||||
| /* KillFace( fDel ) destroys a face and removes it from the global face
 | ||||
|  * list.  It updates the face loop to point to a given new face. | ||||
|  */ | ||||
| static void KillFace( GLUface *fDel, GLUface *newLface ) | ||||
| { | ||||
|   GLUhalfEdge *e, *eStart = fDel->anEdge; | ||||
|   GLUface *fPrev, *fNext; | ||||
| 
 | ||||
|   /* change the left face of all affected edges */ | ||||
|   e = eStart; | ||||
|   do { | ||||
|     e->Lface = newLface; | ||||
|     e = e->Lnext; | ||||
|   } while( e != eStart ); | ||||
| 
 | ||||
|   /* delete from circular doubly-linked list */ | ||||
|   fPrev = fDel->prev; | ||||
|   fNext = fDel->next; | ||||
|   fNext->prev = fPrev; | ||||
|   fPrev->next = fNext; | ||||
| 
 | ||||
|   memFree( fDel ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /****************** Basic Edge Operations **********************/ | ||||
| 
 | ||||
| /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
 | ||||
|  * The loop consists of the two new half-edges. | ||||
|  */ | ||||
| GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUvertex *newVertex1= allocVertex(); | ||||
|   GLUvertex *newVertex2= allocVertex(); | ||||
|   GLUface *newFace= allocFace(); | ||||
|   GLUhalfEdge *e; | ||||
| 
 | ||||
|   /* if any one is null then all get freed */ | ||||
|   if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { | ||||
|      if (newVertex1 != NULL) memFree(newVertex1); | ||||
|      if (newVertex2 != NULL) memFree(newVertex2); | ||||
|      if (newFace != NULL) memFree(newFace);      | ||||
|      return NULL; | ||||
|   }  | ||||
| 
 | ||||
|   e = MakeEdge( &mesh->eHead ); | ||||
|   if (e == NULL) { | ||||
|      memFree(newVertex1); | ||||
|      memFree(newVertex2); | ||||
|      memFree(newFace); | ||||
|      return NULL; | ||||
|   } | ||||
| 
 | ||||
|   MakeVertex( newVertex1, e, &mesh->vHead ); | ||||
|   MakeVertex( newVertex2, e->Sym, &mesh->vHead ); | ||||
|   MakeFace( newFace, e, &mesh->fHead ); | ||||
|   return e; | ||||
| } | ||||
|    | ||||
| 
 | ||||
| /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
 | ||||
|  * mesh connectivity and topology.  It changes the mesh so that | ||||
|  *	eOrg->Onext <- OLD( eDst->Onext ) | ||||
|  *	eDst->Onext <- OLD( eOrg->Onext ) | ||||
|  * where OLD(...) means the value before the meshSplice operation. | ||||
|  * | ||||
|  * This can have two effects on the vertex structure: | ||||
|  *  - if eOrg->Org != eDst->Org, the two vertices are merged together | ||||
|  *  - if eOrg->Org == eDst->Org, the origin is split into two vertices | ||||
|  * In both cases, eDst->Org is changed and eOrg->Org is untouched. | ||||
|  * | ||||
|  * Similarly (and independently) for the face structure, | ||||
|  *  - if eOrg->Lface == eDst->Lface, one loop is split into two | ||||
|  *  - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one | ||||
|  * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. | ||||
|  * | ||||
|  * Some special cases: | ||||
|  * If eDst == eOrg, the operation has no effect. | ||||
|  * If eDst == eOrg->Lnext, the new face will have a single edge. | ||||
|  * If eDst == eOrg->Lprev, the old face will have a single edge. | ||||
|  * If eDst == eOrg->Onext, the new vertex will have a single edge. | ||||
|  * If eDst == eOrg->Oprev, the old vertex will have a single edge. | ||||
|  */ | ||||
| int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) | ||||
| { | ||||
|   int joiningLoops = FALSE; | ||||
|   int joiningVertices = FALSE; | ||||
| 
 | ||||
|   if( eOrg == eDst ) return 1; | ||||
| 
 | ||||
|   if( eDst->Org != eOrg->Org ) { | ||||
|     /* We are merging two disjoint vertices -- destroy eDst->Org */ | ||||
|     joiningVertices = TRUE; | ||||
|     KillVertex( eDst->Org, eOrg->Org ); | ||||
|   } | ||||
|   if( eDst->Lface != eOrg->Lface ) { | ||||
|     /* We are connecting two disjoint loops -- destroy eDst->Lface */ | ||||
|     joiningLoops = TRUE; | ||||
|     KillFace( eDst->Lface, eOrg->Lface ); | ||||
|   } | ||||
| 
 | ||||
|   /* Change the edge structure */ | ||||
|   Splice( eDst, eOrg ); | ||||
| 
 | ||||
|   if( ! joiningVertices ) { | ||||
|     GLUvertex *newVertex= allocVertex(); | ||||
|     if (newVertex == NULL) return 0; | ||||
| 
 | ||||
|     /* We split one vertex into two -- the new vertex is eDst->Org.
 | ||||
|      * Make sure the old vertex points to a valid half-edge. | ||||
|      */ | ||||
|     MakeVertex( newVertex, eDst, eOrg->Org ); | ||||
|     eOrg->Org->anEdge = eOrg; | ||||
|   } | ||||
|   if( ! joiningLoops ) { | ||||
|     GLUface *newFace= allocFace();   | ||||
|     if (newFace == NULL) return 0; | ||||
| 
 | ||||
|     /* We split one loop into two -- the new loop is eDst->Lface.
 | ||||
|      * Make sure the old face points to a valid half-edge. | ||||
|      */ | ||||
|     MakeFace( newFace, eDst, eOrg->Lface ); | ||||
|     eOrg->Lface->anEdge = eOrg; | ||||
|   } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshDelete( eDel ) removes the edge eDel.  There are several cases:
 | ||||
|  * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop | ||||
|  * eDel->Lface is deleted.  Otherwise, we are splitting one loop into two; | ||||
|  * the newly created loop will contain eDel->Dst.  If the deletion of eDel | ||||
|  * would create isolated vertices, those are deleted as well. | ||||
|  * | ||||
|  * This function could be implemented as two calls to __gl_meshSplice | ||||
|  * plus a few calls to memFree, but this would allocate and delete | ||||
|  * unnecessary vertices and faces. | ||||
|  */ | ||||
| int __gl_meshDelete( GLUhalfEdge *eDel ) | ||||
| { | ||||
|   GLUhalfEdge *eDelSym = eDel->Sym; | ||||
|   int joiningLoops = FALSE; | ||||
| 
 | ||||
|   /* First step: disconnect the origin vertex eDel->Org.  We make all
 | ||||
|    * changes to get a consistent mesh in this "intermediate" state. | ||||
|    */ | ||||
|   if( eDel->Lface != eDel->Rface ) { | ||||
|     /* We are joining two loops into one -- remove the left face */ | ||||
|     joiningLoops = TRUE; | ||||
|     KillFace( eDel->Lface, eDel->Rface ); | ||||
|   } | ||||
| 
 | ||||
|   if( eDel->Onext == eDel ) { | ||||
|     KillVertex( eDel->Org, NULL ); | ||||
|   } else { | ||||
|     /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ | ||||
|     eDel->Rface->anEdge = eDel->Oprev; | ||||
|     eDel->Org->anEdge = eDel->Onext; | ||||
| 
 | ||||
|     Splice( eDel, eDel->Oprev ); | ||||
|     if( ! joiningLoops ) { | ||||
|       GLUface *newFace= allocFace(); | ||||
|       if (newFace == NULL) return 0;  | ||||
| 
 | ||||
|       /* We are splitting one loop into two -- create a new loop for eDel. */ | ||||
|       MakeFace( newFace, eDel, eDel->Lface ); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* Claim: the mesh is now in a consistent state, except that eDel->Org
 | ||||
|    * may have been deleted.  Now we disconnect eDel->Dst. | ||||
|    */ | ||||
|   if( eDelSym->Onext == eDelSym ) { | ||||
|     KillVertex( eDelSym->Org, NULL ); | ||||
|     KillFace( eDelSym->Lface, NULL ); | ||||
|   } else { | ||||
|     /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ | ||||
|     eDel->Lface->anEdge = eDelSym->Oprev; | ||||
|     eDelSym->Org->anEdge = eDelSym->Onext; | ||||
|     Splice( eDelSym, eDelSym->Oprev ); | ||||
|   } | ||||
| 
 | ||||
|   /* Any isolated vertices or faces have already been freed. */ | ||||
|   KillEdge( eDel ); | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /******************** Other Edge Operations **********************/ | ||||
| 
 | ||||
| /* All these routines can be implemented with the basic edge
 | ||||
|  * operations above.  They are provided for convenience and efficiency. | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
 | ||||
|  * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. | ||||
|  * eOrg and eNew will have the same left face. | ||||
|  */ | ||||
| GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ) | ||||
| { | ||||
|   GLUhalfEdge *eNewSym; | ||||
|   GLUhalfEdge *eNew = MakeEdge( eOrg ); | ||||
|   if (eNew == NULL) return NULL; | ||||
| 
 | ||||
|   eNewSym = eNew->Sym; | ||||
| 
 | ||||
|   /* Connect the new edge appropriately */ | ||||
|   Splice( eNew, eOrg->Lnext ); | ||||
| 
 | ||||
|   /* Set the vertex and face information */ | ||||
|   eNew->Org = eOrg->Dst; | ||||
|   { | ||||
|     GLUvertex *newVertex= allocVertex(); | ||||
|     if (newVertex == NULL) return NULL; | ||||
| 
 | ||||
|     MakeVertex( newVertex, eNewSym, eNew->Org ); | ||||
|   } | ||||
|   eNew->Lface = eNewSym->Lface = eOrg->Lface; | ||||
| 
 | ||||
|   return eNew; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
 | ||||
|  * such that eNew == eOrg->Lnext.  The new vertex is eOrg->Dst == eNew->Org. | ||||
|  * eOrg and eNew will have the same left face. | ||||
|  */ | ||||
| GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ) | ||||
| { | ||||
|   GLUhalfEdge *eNew; | ||||
|   GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg ); | ||||
|   if (tempHalfEdge == NULL) return NULL; | ||||
| 
 | ||||
|   eNew = tempHalfEdge->Sym; | ||||
| 
 | ||||
|   /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ | ||||
|   Splice( eOrg->Sym, eOrg->Sym->Oprev ); | ||||
|   Splice( eOrg->Sym, eNew ); | ||||
| 
 | ||||
|   /* Set the vertex and face information */ | ||||
|   eOrg->Dst = eNew->Org; | ||||
|   eNew->Dst->anEdge = eNew->Sym;	/* may have pointed to eOrg->Sym */ | ||||
|   eNew->Rface = eOrg->Rface; | ||||
|   eNew->winding = eOrg->winding;	/* copy old winding information */ | ||||
|   eNew->Sym->winding = eOrg->Sym->winding; | ||||
| 
 | ||||
|   return eNew; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
 | ||||
|  * to eDst->Org, and returns the corresponding half-edge eNew. | ||||
|  * If eOrg->Lface == eDst->Lface, this splits one loop into two, | ||||
|  * and the newly created loop is eNew->Lface.  Otherwise, two disjoint | ||||
|  * loops are merged into one, and the loop eDst->Lface is destroyed. | ||||
|  * | ||||
|  * If (eOrg == eDst), the new face will have only two edges. | ||||
|  * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. | ||||
|  * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. | ||||
|  */ | ||||
| GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) | ||||
| { | ||||
|   GLUhalfEdge *eNewSym; | ||||
|   int joiningLoops = FALSE;   | ||||
|   GLUhalfEdge *eNew = MakeEdge( eOrg ); | ||||
|   if (eNew == NULL) return NULL; | ||||
| 
 | ||||
|   eNewSym = eNew->Sym; | ||||
| 
 | ||||
|   if( eDst->Lface != eOrg->Lface ) { | ||||
|     /* We are connecting two disjoint loops -- destroy eDst->Lface */ | ||||
|     joiningLoops = TRUE; | ||||
|     KillFace( eDst->Lface, eOrg->Lface ); | ||||
|   } | ||||
| 
 | ||||
|   /* Connect the new edge appropriately */ | ||||
|   Splice( eNew, eOrg->Lnext ); | ||||
|   Splice( eNewSym, eDst ); | ||||
| 
 | ||||
|   /* Set the vertex and face information */ | ||||
|   eNew->Org = eOrg->Dst; | ||||
|   eNewSym->Org = eDst->Org; | ||||
|   eNew->Lface = eNewSym->Lface = eOrg->Lface; | ||||
| 
 | ||||
|   /* Make sure the old face points to a valid half-edge */ | ||||
|   eOrg->Lface->anEdge = eNewSym; | ||||
| 
 | ||||
|   if( ! joiningLoops ) { | ||||
|     GLUface *newFace= allocFace(); | ||||
|     if (newFace == NULL) return NULL; | ||||
| 
 | ||||
|     /* We split one loop into two -- the new loop is eNew->Lface */ | ||||
|     MakeFace( newFace, eNew, eOrg->Lface ); | ||||
|   } | ||||
|   return eNew; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /******************** Other Operations **********************/ | ||||
| 
 | ||||
| /* __gl_meshZapFace( fZap ) destroys a face and removes it from the
 | ||||
|  * global face list.  All edges of fZap will have a NULL pointer as their | ||||
|  * left face.  Any edges which also have a NULL pointer as their right face | ||||
|  * are deleted entirely (along with any isolated vertices this produces). | ||||
|  * An entire mesh can be deleted by zapping its faces, one at a time, | ||||
|  * in any order.  Zapped faces cannot be used in further mesh operations! | ||||
|  */ | ||||
| void __gl_meshZapFace( GLUface *fZap ) | ||||
| { | ||||
|   GLUhalfEdge *eStart = fZap->anEdge; | ||||
|   GLUhalfEdge *e, *eNext, *eSym; | ||||
|   GLUface *fPrev, *fNext; | ||||
| 
 | ||||
|   /* walk around face, deleting edges whose right face is also NULL */ | ||||
|   eNext = eStart->Lnext; | ||||
|   do { | ||||
|     e = eNext; | ||||
|     eNext = e->Lnext; | ||||
| 
 | ||||
|     e->Lface = NULL; | ||||
|     if( e->Rface == NULL ) { | ||||
|       /* delete the edge -- see __gl_MeshDelete above */ | ||||
| 
 | ||||
|       if( e->Onext == e ) { | ||||
| 	KillVertex( e->Org, NULL ); | ||||
|       } else { | ||||
| 	/* Make sure that e->Org points to a valid half-edge */ | ||||
| 	e->Org->anEdge = e->Onext; | ||||
| 	Splice( e, e->Oprev ); | ||||
|       } | ||||
|       eSym = e->Sym; | ||||
|       if( eSym->Onext == eSym ) { | ||||
| 	KillVertex( eSym->Org, NULL ); | ||||
|       } else { | ||||
| 	/* Make sure that eSym->Org points to a valid half-edge */ | ||||
| 	eSym->Org->anEdge = eSym->Onext; | ||||
| 	Splice( eSym, eSym->Oprev ); | ||||
|       } | ||||
|       KillEdge( e ); | ||||
|     } | ||||
|   } while( e != eStart ); | ||||
| 
 | ||||
|   /* delete from circular doubly-linked list */ | ||||
|   fPrev = fZap->prev; | ||||
|   fNext = fZap->next; | ||||
|   fNext->prev = fPrev; | ||||
|   fPrev->next = fNext; | ||||
| 
 | ||||
|   memFree( fZap ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
 | ||||
|  * and no loops (what we usually call a "face"). | ||||
|  */ | ||||
| GLUmesh *__gl_meshNewMesh( void ) | ||||
| { | ||||
|   GLUvertex *v; | ||||
|   GLUface *f; | ||||
|   GLUhalfEdge *e; | ||||
|   GLUhalfEdge *eSym; | ||||
|   GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh )); | ||||
|   if (mesh == NULL) { | ||||
|      return NULL; | ||||
|   } | ||||
|    | ||||
|   v = &mesh->vHead; | ||||
|   f = &mesh->fHead; | ||||
|   e = &mesh->eHead; | ||||
|   eSym = &mesh->eHeadSym; | ||||
| 
 | ||||
|   v->next = v->prev = v; | ||||
|   v->anEdge = NULL; | ||||
|   v->data = NULL; | ||||
| 
 | ||||
|   f->next = f->prev = f; | ||||
|   f->anEdge = NULL; | ||||
|   f->data = NULL; | ||||
|   f->trail = NULL; | ||||
|   f->marked = FALSE; | ||||
|   f->inside = FALSE; | ||||
| 
 | ||||
|   e->next = e; | ||||
|   e->Sym = eSym; | ||||
|   e->Onext = NULL; | ||||
|   e->Lnext = NULL; | ||||
|   e->Org = NULL; | ||||
|   e->Lface = NULL; | ||||
|   e->winding = 0; | ||||
|   e->activeRegion = NULL; | ||||
| 
 | ||||
|   eSym->next = eSym; | ||||
|   eSym->Sym = e; | ||||
|   eSym->Onext = NULL; | ||||
|   eSym->Lnext = NULL; | ||||
|   eSym->Org = NULL; | ||||
|   eSym->Lface = NULL; | ||||
|   eSym->winding = 0; | ||||
|   eSym->activeRegion = NULL; | ||||
| 
 | ||||
|   return mesh; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
 | ||||
|  * both meshes, and returns the new mesh (the old meshes are destroyed). | ||||
|  */ | ||||
| GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ) | ||||
| { | ||||
|   GLUface *f1 = &mesh1->fHead; | ||||
|   GLUvertex *v1 = &mesh1->vHead; | ||||
|   GLUhalfEdge *e1 = &mesh1->eHead; | ||||
|   GLUface *f2 = &mesh2->fHead; | ||||
|   GLUvertex *v2 = &mesh2->vHead; | ||||
|   GLUhalfEdge *e2 = &mesh2->eHead; | ||||
| 
 | ||||
|   /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ | ||||
|   if( f2->next != f2 ) { | ||||
|     f1->prev->next = f2->next; | ||||
|     f2->next->prev = f1->prev; | ||||
|     f2->prev->next = f1; | ||||
|     f1->prev = f2->prev; | ||||
|   } | ||||
| 
 | ||||
|   if( v2->next != v2 ) { | ||||
|     v1->prev->next = v2->next; | ||||
|     v2->next->prev = v1->prev; | ||||
|     v2->prev->next = v1; | ||||
|     v1->prev = v2->prev; | ||||
|   } | ||||
| 
 | ||||
|   if( e2->next != e2 ) { | ||||
|     e1->Sym->next->Sym->next = e2->next; | ||||
|     e2->next->Sym->next = e1->Sym->next; | ||||
|     e2->Sym->next->Sym->next = e1; | ||||
|     e1->Sym->next = e2->Sym->next; | ||||
|   } | ||||
| 
 | ||||
|   memFree( mesh2 ); | ||||
|   return mesh1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifdef DELETE_BY_ZAPPING | ||||
| 
 | ||||
| /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
 | ||||
|  */ | ||||
| void __gl_meshDeleteMesh( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *fHead = &mesh->fHead; | ||||
| 
 | ||||
|   while( fHead->next != fHead ) { | ||||
|     __gl_meshZapFace( fHead->next ); | ||||
|   } | ||||
|   assert( mesh->vHead.next == &mesh->vHead ); | ||||
| 
 | ||||
|   memFree( mesh ); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
 | ||||
|  */ | ||||
| void __gl_meshDeleteMesh( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *f, *fNext; | ||||
|   GLUvertex *v, *vNext; | ||||
|   GLUhalfEdge *e, *eNext; | ||||
| 
 | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { | ||||
|     fNext = f->next; | ||||
|     memFree( f ); | ||||
|   } | ||||
| 
 | ||||
|   for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) { | ||||
|     vNext = v->next; | ||||
|     memFree( v ); | ||||
|   } | ||||
| 
 | ||||
|   for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { | ||||
|     /* One call frees both e and e->Sym (see EdgePair above) */ | ||||
|     eNext = e->next; | ||||
|     memFree( e ); | ||||
|   } | ||||
| 
 | ||||
|   memFree( mesh ); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef NDEBUG | ||||
| 
 | ||||
| /* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
 | ||||
|  */ | ||||
| void __gl_meshCheckMesh( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *fHead = &mesh->fHead; | ||||
|   GLUvertex *vHead = &mesh->vHead; | ||||
|   GLUhalfEdge *eHead = &mesh->eHead; | ||||
|   GLUface *f, *fPrev; | ||||
|   GLUvertex *v, *vPrev; | ||||
|   GLUhalfEdge *e, *ePrev; | ||||
| 
 | ||||
|   fPrev = fHead; | ||||
|   for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { | ||||
|     assert( f->prev == fPrev ); | ||||
|     e = f->anEdge; | ||||
|     do { | ||||
|       assert( e->Sym != e ); | ||||
|       assert( e->Sym->Sym == e ); | ||||
|       assert( e->Lnext->Onext->Sym == e ); | ||||
|       assert( e->Onext->Sym->Lnext == e ); | ||||
|       assert( e->Lface == f ); | ||||
|       e = e->Lnext; | ||||
|     } while( e != f->anEdge ); | ||||
|   } | ||||
|   assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL ); | ||||
| 
 | ||||
|   vPrev = vHead; | ||||
|   for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { | ||||
|     assert( v->prev == vPrev ); | ||||
|     e = v->anEdge; | ||||
|     do { | ||||
|       assert( e->Sym != e ); | ||||
|       assert( e->Sym->Sym == e ); | ||||
|       assert( e->Lnext->Onext->Sym == e ); | ||||
|       assert( e->Onext->Sym->Lnext == e ); | ||||
|       assert( e->Org == v ); | ||||
|       e = e->Onext; | ||||
|     } while( e != v->anEdge ); | ||||
|   } | ||||
|   assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL ); | ||||
| 
 | ||||
|   ePrev = eHead; | ||||
|   for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { | ||||
|     assert( e->Sym->next == ePrev->Sym ); | ||||
|     assert( e->Sym != e ); | ||||
|     assert( e->Sym->Sym == e ); | ||||
|     assert( e->Org != NULL ); | ||||
|     assert( e->Dst != NULL ); | ||||
|     assert( e->Lnext->Onext->Sym == e ); | ||||
|     assert( e->Onext->Sym->Lnext == e ); | ||||
|   } | ||||
|   assert( e->Sym->next == ePrev->Sym | ||||
|        && e->Sym == &mesh->eHeadSym | ||||
|        && e->Sym->Sym == e | ||||
|        && e->Org == NULL && e->Dst == NULL | ||||
|        && e->Lface == NULL && e->Rface == NULL ); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										266
									
								
								src/glu-libtess/src/mesh.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								src/glu-libtess/src/mesh.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,266 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __mesh_h_ | ||||
| #define __mesh_h_ | ||||
| 
 | ||||
| #include "glu-libtess.h" | ||||
| 
 | ||||
| typedef struct GLUmesh GLUmesh;  | ||||
| 
 | ||||
| typedef struct GLUvertex GLUvertex; | ||||
| typedef struct GLUface GLUface; | ||||
| typedef struct GLUhalfEdge GLUhalfEdge; | ||||
| 
 | ||||
| typedef struct ActiveRegion ActiveRegion;	/* Internal data */ | ||||
| 
 | ||||
| /* The mesh structure is similar in spirit, notation, and operations
 | ||||
|  * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives | ||||
|  * for the manipulation of general subdivisions and the computation of | ||||
|  * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). | ||||
|  * For a simplified description, see the course notes for CS348a, | ||||
|  * "Mathematical Foundations of Computer Graphics", available at the | ||||
|  * Stanford bookstore (and taught during the fall quarter). | ||||
|  * The implementation also borrows a tiny subset of the graph-based approach | ||||
|  * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction | ||||
|  * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). | ||||
|  * | ||||
|  * The fundamental data structure is the "half-edge".  Two half-edges | ||||
|  * go together to make an edge, but they point in opposite directions. | ||||
|  * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), | ||||
|  * its origin vertex (Org), the face on its left side (Lface), and the | ||||
|  * adjacent half-edges in the CCW direction around the origin vertex | ||||
|  * (Onext) and around the left face (Lnext).  There is also a "next" | ||||
|  * pointer for the global edge list (see below). | ||||
|  * | ||||
|  * The notation used for mesh navigation: | ||||
|  *	Sym   = the mate of a half-edge (same edge, but opposite direction) | ||||
|  *	Onext = edge CCW around origin vertex (keep same origin) | ||||
|  *	Dnext = edge CCW around destination vertex (keep same dest) | ||||
|  *	Lnext = edge CCW around left face (dest becomes new origin) | ||||
|  *	Rnext = edge CCW around right face (origin becomes new dest) | ||||
|  * | ||||
|  * "prev" means to substitute CW for CCW in the definitions above. | ||||
|  * | ||||
|  * The mesh keeps global lists of all vertices, faces, and edges, | ||||
|  * stored as doubly-linked circular lists with a dummy header node. | ||||
|  * The mesh stores pointers to these dummy headers (vHead, fHead, eHead). | ||||
|  * | ||||
|  * The circular edge list is special; since half-edges always occur | ||||
|  * in pairs (e and e->Sym), each half-edge stores a pointer in only | ||||
|  * one direction.  Starting at eHead and following the e->next pointers | ||||
|  * will visit each *edge* once (ie. e or e->Sym, but not both). | ||||
|  * e->Sym stores a pointer in the opposite direction, thus it is | ||||
|  * always true that e->Sym->next->Sym->next == e. | ||||
|  * | ||||
|  * Each vertex has a pointer to next and previous vertices in the | ||||
|  * circular list, and a pointer to a half-edge with this vertex as | ||||
|  * the origin (NULL if this is the dummy header).  There is also a | ||||
|  * field "data" for client data. | ||||
|  * | ||||
|  * Each face has a pointer to the next and previous faces in the | ||||
|  * circular list, and a pointer to a half-edge with this face as | ||||
|  * the left face (NULL if this is the dummy header).  There is also | ||||
|  * a field "data" for client data. | ||||
|  * | ||||
|  * Note that what we call a "face" is really a loop; faces may consist | ||||
|  * of more than one loop (ie. not simply connected), but there is no | ||||
|  * record of this in the data structure.  The mesh may consist of | ||||
|  * several disconnected regions, so it may not be possible to visit | ||||
|  * the entire mesh by starting at a half-edge and traversing the edge | ||||
|  * structure. | ||||
|  * | ||||
|  * The mesh does NOT support isolated vertices; a vertex is deleted along | ||||
|  * with its last edge.  Similarly when two faces are merged, one of the | ||||
|  * faces is deleted (see __gl_meshDelete below).  For mesh operations, | ||||
|  * all face (loop) and vertex pointers must not be NULL.  However, once | ||||
|  * mesh manipulation is finished, __gl_MeshZapFace can be used to delete | ||||
|  * faces of the mesh, one at a time.  All external faces can be "zapped" | ||||
|  * before the mesh is returned to the client; then a NULL face indicates | ||||
|  * a region which is not part of the output polygon. | ||||
|  */ | ||||
| 
 | ||||
| struct GLUvertex { | ||||
|   GLUvertex	*next;		/* next vertex (never NULL) */ | ||||
|   GLUvertex	*prev;		/* previous vertex (never NULL) */ | ||||
|   GLUhalfEdge	*anEdge;	/* a half-edge with this origin */ | ||||
|   void		*data;		/* client's data */ | ||||
| 
 | ||||
|   /* Internal data (keep hidden) */ | ||||
|   GLdouble	coords[3];	/* vertex location in 3D */ | ||||
|   GLdouble	s, t;		/* projection onto the sweep plane */ | ||||
|   long		pqHandle;	/* to allow deletion from priority queue */ | ||||
| }; | ||||
| 
 | ||||
| struct GLUface { | ||||
|   GLUface	*next;		/* next face (never NULL) */ | ||||
|   GLUface	*prev;		/* previous face (never NULL) */ | ||||
|   GLUhalfEdge	*anEdge;	/* a half edge with this left face */ | ||||
|   void		*data;		/* room for client's data */ | ||||
| 
 | ||||
|   /* Internal data (keep hidden) */ | ||||
|   GLUface	*trail;		/* "stack" for conversion to strips */ | ||||
|   GLboolean	marked;		/* flag for conversion to strips */ | ||||
|   GLboolean	inside;		/* this face is in the polygon interior */ | ||||
| }; | ||||
| 
 | ||||
| struct GLUhalfEdge { | ||||
|   GLUhalfEdge	*next;		/* doubly-linked list (prev==Sym->next) */ | ||||
|   GLUhalfEdge	*Sym;		/* same edge, opposite direction */ | ||||
|   GLUhalfEdge	*Onext;		/* next edge CCW around origin */ | ||||
|   GLUhalfEdge	*Lnext;		/* next edge CCW around left face */ | ||||
|   GLUvertex	*Org;		/* origin vertex (Overtex too long) */ | ||||
|   GLUface	*Lface;		/* left face */ | ||||
| 
 | ||||
|   /* Internal data (keep hidden) */ | ||||
|   ActiveRegion	*activeRegion;	/* a region with this upper edge (sweep.c) */ | ||||
|   int		winding;	/* change in winding number when crossing
 | ||||
|                                    from the right face to the left face */ | ||||
| }; | ||||
| 
 | ||||
| #define	Rface	Sym->Lface | ||||
| #define Dst	Sym->Org | ||||
| 
 | ||||
| #define Oprev	Sym->Lnext | ||||
| #define Lprev   Onext->Sym | ||||
| #define Dprev	Lnext->Sym | ||||
| #define Rprev	Sym->Onext | ||||
| #define Dnext	Rprev->Sym	/* 3 pointers */ | ||||
| #define Rnext	Oprev->Sym	/* 3 pointers */ | ||||
| 
 | ||||
| 
 | ||||
| struct GLUmesh { | ||||
|   GLUvertex	vHead;		/* dummy header for vertex list */ | ||||
|   GLUface	fHead;		/* dummy header for face list */ | ||||
|   GLUhalfEdge	eHead;		/* dummy header for edge list */ | ||||
|   GLUhalfEdge	eHeadSym;	/* and its symmetric counterpart */ | ||||
| }; | ||||
| 
 | ||||
| /* The mesh operations below have three motivations: completeness,
 | ||||
|  * convenience, and efficiency.  The basic mesh operations are MakeEdge, | ||||
|  * Splice, and Delete.  All the other edge operations can be implemented | ||||
|  * in terms of these.  The other operations are provided for convenience | ||||
|  * and/or efficiency. | ||||
|  * | ||||
|  * When a face is split or a vertex is added, they are inserted into the | ||||
|  * global list *before* the existing vertex or face (ie. e->Org or e->Lface). | ||||
|  * This makes it easier to process all vertices or faces in the global lists | ||||
|  * without worrying about processing the same data twice.  As a convenience, | ||||
|  * when a face is split, the "inside" flag is copied from the old face. | ||||
|  * Other internal data (v->data, v->activeRegion, f->data, f->marked, | ||||
|  * f->trail, e->winding) is set to zero. | ||||
|  * | ||||
|  * ********************** Basic Edge Operations ************************** | ||||
|  * | ||||
|  * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop. | ||||
|  * The loop (face) consists of the two new half-edges. | ||||
|  * | ||||
|  * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the | ||||
|  * mesh connectivity and topology.  It changes the mesh so that | ||||
|  *	eOrg->Onext <- OLD( eDst->Onext ) | ||||
|  *	eDst->Onext <- OLD( eOrg->Onext ) | ||||
|  * where OLD(...) means the value before the meshSplice operation. | ||||
|  * | ||||
|  * This can have two effects on the vertex structure: | ||||
|  *  - if eOrg->Org != eDst->Org, the two vertices are merged together | ||||
|  *  - if eOrg->Org == eDst->Org, the origin is split into two vertices | ||||
|  * In both cases, eDst->Org is changed and eOrg->Org is untouched. | ||||
|  * | ||||
|  * Similarly (and independently) for the face structure, | ||||
|  *  - if eOrg->Lface == eDst->Lface, one loop is split into two | ||||
|  *  - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one | ||||
|  * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. | ||||
|  * | ||||
|  * __gl_meshDelete( eDel ) removes the edge eDel.  There are several cases: | ||||
|  * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop | ||||
|  * eDel->Lface is deleted.  Otherwise, we are splitting one loop into two; | ||||
|  * the newly created loop will contain eDel->Dst.  If the deletion of eDel | ||||
|  * would create isolated vertices, those are deleted as well. | ||||
|  * | ||||
|  * ********************** Other Edge Operations ************************** | ||||
|  * | ||||
|  * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that | ||||
|  * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. | ||||
|  * eOrg and eNew will have the same left face. | ||||
|  * | ||||
|  * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, | ||||
|  * such that eNew == eOrg->Lnext.  The new vertex is eOrg->Dst == eNew->Org. | ||||
|  * eOrg and eNew will have the same left face. | ||||
|  * | ||||
|  * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst | ||||
|  * to eDst->Org, and returns the corresponding half-edge eNew. | ||||
|  * If eOrg->Lface == eDst->Lface, this splits one loop into two, | ||||
|  * and the newly created loop is eNew->Lface.  Otherwise, two disjoint | ||||
|  * loops are merged into one, and the loop eDst->Lface is destroyed. | ||||
|  * | ||||
|  * ************************ Other Operations ***************************** | ||||
|  * | ||||
|  * __gl_meshNewMesh() creates a new mesh with no edges, no vertices, | ||||
|  * and no loops (what we usually call a "face"). | ||||
|  * | ||||
|  * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in | ||||
|  * both meshes, and returns the new mesh (the old meshes are destroyed). | ||||
|  * | ||||
|  * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. | ||||
|  * | ||||
|  * __gl_meshZapFace( fZap ) destroys a face and removes it from the | ||||
|  * global face list.  All edges of fZap will have a NULL pointer as their | ||||
|  * left face.  Any edges which also have a NULL pointer as their right face | ||||
|  * are deleted entirely (along with any isolated vertices this produces). | ||||
|  * An entire mesh can be deleted by zapping its faces, one at a time, | ||||
|  * in any order.  Zapped faces cannot be used in further mesh operations! | ||||
|  * | ||||
|  * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. | ||||
|  */ | ||||
| 
 | ||||
| GLUhalfEdge	*__gl_meshMakeEdge( GLUmesh *mesh ); | ||||
| int		__gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); | ||||
| int		__gl_meshDelete( GLUhalfEdge *eDel ); | ||||
| 
 | ||||
| GLUhalfEdge	*__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ); | ||||
| GLUhalfEdge	*__gl_meshSplitEdge( GLUhalfEdge *eOrg ); | ||||
| GLUhalfEdge	*__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); | ||||
| 
 | ||||
| GLUmesh		*__gl_meshNewMesh( void ); | ||||
| GLUmesh		*__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ); | ||||
| void		__gl_meshDeleteMesh( GLUmesh *mesh ); | ||||
| void		__gl_meshZapFace( GLUface *fZap ); | ||||
| 
 | ||||
| #ifdef NDEBUG | ||||
| #define		__gl_meshCheckMesh( mesh ) | ||||
| #else | ||||
| void		__gl_meshCheckMesh( GLUmesh *mesh ); | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										257
									
								
								src/glu-libtess/src/normal.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/glu-libtess/src/normal.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,257 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include "mesh.h" | ||||
| #include "tess.h" | ||||
| #include "normal.h" | ||||
| #include <math.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #ifndef TRUE | ||||
| #define TRUE 1 | ||||
| #endif | ||||
| #ifndef FALSE | ||||
| #define FALSE 0 | ||||
| #endif | ||||
| 
 | ||||
| #define Dot(u,v)	(u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) | ||||
| 
 | ||||
| #if 0 | ||||
| static void Normalize( GLdouble v[3] ) | ||||
| { | ||||
|   GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; | ||||
| 
 | ||||
|   assert( len > 0 ); | ||||
|   len = sqrt( len ); | ||||
|   v[0] /= len; | ||||
|   v[1] /= len; | ||||
|   v[2] /= len; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #undef	ABS | ||||
| #define ABS(x)	((x) < 0 ? -(x) : (x)) | ||||
| 
 | ||||
| static int LongAxis( GLdouble v[3] ) | ||||
| { | ||||
|   int i = 0; | ||||
| 
 | ||||
|   if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } | ||||
|   if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } | ||||
|   return i; | ||||
| } | ||||
| 
 | ||||
| static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) | ||||
| { | ||||
|   GLUvertex *v, *v1, *v2; | ||||
|   GLdouble c, tLen2, maxLen2; | ||||
|   GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; | ||||
|   GLUvertex *maxVert[3], *minVert[3]; | ||||
|   GLUvertex *vHead = &tess->mesh->vHead; | ||||
|   int i; | ||||
| 
 | ||||
|   maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; | ||||
|   minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; | ||||
| 
 | ||||
|   for( v = vHead->next; v != vHead; v = v->next ) { | ||||
|     for( i = 0; i < 3; ++i ) { | ||||
|       c = v->coords[i]; | ||||
|       if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } | ||||
|       if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* Find two vertices separated by at least 1/sqrt(3) of the maximum
 | ||||
|    * distance between any two vertices | ||||
|    */ | ||||
|   i = 0; | ||||
|   if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } | ||||
|   if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } | ||||
|   if( minVal[i] >= maxVal[i] ) { | ||||
|     /* All vertices are the same -- normal doesn't matter */ | ||||
|     norm[0] = 0; norm[1] = 0; norm[2] = 1; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   /* Look for a third vertex which forms the triangle with maximum area
 | ||||
|    * (Length of normal == twice the triangle area) | ||||
|    */ | ||||
|   maxLen2 = 0; | ||||
|   v1 = minVert[i]; | ||||
|   v2 = maxVert[i]; | ||||
|   d1[0] = v1->coords[0] - v2->coords[0]; | ||||
|   d1[1] = v1->coords[1] - v2->coords[1]; | ||||
|   d1[2] = v1->coords[2] - v2->coords[2]; | ||||
|   for( v = vHead->next; v != vHead; v = v->next ) { | ||||
|     d2[0] = v->coords[0] - v2->coords[0]; | ||||
|     d2[1] = v->coords[1] - v2->coords[1]; | ||||
|     d2[2] = v->coords[2] - v2->coords[2]; | ||||
|     tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; | ||||
|     tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; | ||||
|     tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; | ||||
|     tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; | ||||
|     if( tLen2 > maxLen2 ) { | ||||
|       maxLen2 = tLen2; | ||||
|       norm[0] = tNorm[0]; | ||||
|       norm[1] = tNorm[1]; | ||||
|       norm[2] = tNorm[2]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if( maxLen2 <= 0 ) { | ||||
|     /* All points lie on a single line -- any decent normal will do */ | ||||
|     norm[0] = norm[1] = norm[2] = 0; | ||||
|     norm[LongAxis(d1)] = 1; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void CheckOrientation( GLUtesselator *tess ) | ||||
| { | ||||
|   GLdouble area; | ||||
|   GLUface *f, *fHead = &tess->mesh->fHead; | ||||
|   GLUvertex *v, *vHead = &tess->mesh->vHead; | ||||
|   GLUhalfEdge *e; | ||||
| 
 | ||||
|   /* When we compute the normal automatically, we choose the orientation
 | ||||
|    * so that the sum of the signed areas of all contours is non-negative. | ||||
|    */ | ||||
|   area = 0; | ||||
|   for( f = fHead->next; f != fHead; f = f->next ) { | ||||
|     e = f->anEdge; | ||||
|     if( e->winding <= 0 ) continue; | ||||
|     do { | ||||
|       area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); | ||||
|       e = e->Lnext; | ||||
|     } while( e != f->anEdge ); | ||||
|   } | ||||
|   if( area < 0 ) { | ||||
|     /* Reverse the orientation by flipping all the t-coordinates */ | ||||
|     for( v = vHead->next; v != vHead; v = v->next ) { | ||||
|       v->t = - v->t; | ||||
|     } | ||||
|     tess->tUnit[0] = - tess->tUnit[0]; | ||||
|     tess->tUnit[1] = - tess->tUnit[1]; | ||||
|     tess->tUnit[2] = - tess->tUnit[2]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #ifdef FOR_TRITE_TEST_PROGRAM | ||||
| #include <stdlib.h> | ||||
| extern int RandomSweep; | ||||
| #define S_UNIT_X	(RandomSweep ? (2*drand48()-1) : 1.0) | ||||
| #define S_UNIT_Y	(RandomSweep ? (2*drand48()-1) : 0.0) | ||||
| #else | ||||
| #if defined(SLANTED_SWEEP) | ||||
| /* The "feature merging" is not intended to be complete.  There are
 | ||||
|  * special cases where edges are nearly parallel to the sweep line | ||||
|  * which are not implemented.  The algorithm should still behave | ||||
|  * robustly (ie. produce a reasonable tesselation) in the presence | ||||
|  * of such edges, however it may miss features which could have been | ||||
|  * merged.  We could minimize this effect by choosing the sweep line | ||||
|  * direction to be something unusual (ie. not parallel to one of the | ||||
|  * coordinate axes). | ||||
|  */ | ||||
| #define S_UNIT_X	0.50941539564955385	/* Pre-normalized */ | ||||
| #define S_UNIT_Y	0.86052074622010633 | ||||
| #else | ||||
| #define S_UNIT_X	1.0 | ||||
| #define S_UNIT_Y	0.0 | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| /* Determine the polygon normal and project vertices onto the plane
 | ||||
|  * of the polygon. | ||||
|  */ | ||||
| void __gl_projectPolygon( GLUtesselator *tess ) | ||||
| { | ||||
|   GLUvertex *v, *vHead = &tess->mesh->vHead; | ||||
|   GLdouble norm[3]; | ||||
|   GLdouble *sUnit, *tUnit; | ||||
|   int i, computedNormal = FALSE; | ||||
| 
 | ||||
|   norm[0] = tess->normal[0]; | ||||
|   norm[1] = tess->normal[1]; | ||||
|   norm[2] = tess->normal[2]; | ||||
|   if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { | ||||
|     ComputeNormal( tess, norm ); | ||||
|     computedNormal = TRUE; | ||||
|   } | ||||
|   sUnit = tess->sUnit; | ||||
|   tUnit = tess->tUnit; | ||||
|   i = LongAxis( norm ); | ||||
| 
 | ||||
| #if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) | ||||
|   /* Choose the initial sUnit vector to be approximately perpendicular
 | ||||
|    * to the normal. | ||||
|    */ | ||||
|   Normalize( norm ); | ||||
| 
 | ||||
|   sUnit[i] = 0; | ||||
|   sUnit[(i+1)%3] = S_UNIT_X; | ||||
|   sUnit[(i+2)%3] = S_UNIT_Y; | ||||
| 
 | ||||
|   /* Now make it exactly perpendicular */ | ||||
|   w = Dot( sUnit, norm ); | ||||
|   sUnit[0] -= w * norm[0]; | ||||
|   sUnit[1] -= w * norm[1]; | ||||
|   sUnit[2] -= w * norm[2]; | ||||
|   Normalize( sUnit ); | ||||
| 
 | ||||
|   /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ | ||||
|   tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; | ||||
|   tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; | ||||
|   tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; | ||||
|   Normalize( tUnit ); | ||||
| #else | ||||
|   /* Project perpendicular to a coordinate axis -- better numerically */ | ||||
|   sUnit[i] = 0; | ||||
|   sUnit[(i+1)%3] = S_UNIT_X; | ||||
|   sUnit[(i+2)%3] = S_UNIT_Y; | ||||
| 
 | ||||
|   tUnit[i] = 0; | ||||
|   tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; | ||||
|   tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; | ||||
| #endif | ||||
| 
 | ||||
|   /* Project the vertices onto the sweep plane */ | ||||
|   for( v = vHead->next; v != vHead; v = v->next ) { | ||||
|     v->s = Dot( v->coords, sUnit ); | ||||
|     v->t = Dot( v->coords, tUnit ); | ||||
|   } | ||||
|   if( computedNormal ) { | ||||
|     CheckOrientation( tess ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/glu-libtess/src/normal.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/glu-libtess/src/normal.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __normal_h_ | ||||
| #define __normal_h_ | ||||
| 
 | ||||
| #include "tess.h" | ||||
| 
 | ||||
| /* __gl_projectPolygon( tess ) determines the polygon normal
 | ||||
|  * and project vertices onto the plane of the polygon. | ||||
|  */ | ||||
| void __gl_projectPolygon( GLUtesselator *tess ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										256
									
								
								src/glu-libtess/src/priorityq-heap.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								src/glu-libtess/src/priorityq-heap.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,256 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| #include "priorityq-heap.h" | ||||
| #include "memalloc.h" | ||||
| 
 | ||||
| #define INIT_SIZE	32 | ||||
| 
 | ||||
| #ifndef TRUE | ||||
| #define TRUE 1 | ||||
| #endif | ||||
| #ifndef FALSE | ||||
| #define FALSE 0 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef FOR_TRITE_TEST_PROGRAM | ||||
| #define LEQ(x,y)	(*pq->leq)(x,y) | ||||
| #else | ||||
| /* Violates modularity, but a little faster */ | ||||
| #include "geom.h" | ||||
| #define LEQ(x,y)	VertLeq((GLUvertex *)x, (GLUvertex *)y) | ||||
| #endif | ||||
| 
 | ||||
| /* really __gl_pqHeapNewPriorityQ */ | ||||
| PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) | ||||
| { | ||||
|   PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); | ||||
|   if (pq == NULL) return NULL; | ||||
| 
 | ||||
|   pq->size = 0; | ||||
|   pq->max = INIT_SIZE; | ||||
|   pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) ); | ||||
|   if (pq->nodes == NULL) { | ||||
|      memFree(pq); | ||||
|      return NULL; | ||||
|   } | ||||
| 
 | ||||
|   pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) ); | ||||
|   if (pq->handles == NULL) { | ||||
|      memFree(pq->nodes); | ||||
|      memFree(pq); | ||||
|      return NULL; | ||||
|   } | ||||
| 
 | ||||
|   pq->initialized = FALSE; | ||||
|   pq->freeList = 0; | ||||
|   pq->leq = leq; | ||||
| 
 | ||||
|   pq->nodes[1].handle = 1;	/* so that Minimum() returns NULL */ | ||||
|   pq->handles[1].key = NULL; | ||||
|   return pq; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqHeapDeletePriorityQ */ | ||||
| void pqDeletePriorityQ( PriorityQ *pq ) | ||||
| { | ||||
|   memFree( pq->handles ); | ||||
|   memFree( pq->nodes ); | ||||
|   memFree( pq ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void FloatDown( PriorityQ *pq, long curr ) | ||||
| { | ||||
|   PQnode *n = pq->nodes; | ||||
|   PQhandleElem *h = pq->handles; | ||||
|   PQhandle hCurr, hChild; | ||||
|   long child; | ||||
| 
 | ||||
|   hCurr = n[curr].handle; | ||||
|   for( ;; ) { | ||||
|     child = curr << 1; | ||||
|     if( child < pq->size && LEQ( h[n[child+1].handle].key, | ||||
| 				 h[n[child].handle].key )) { | ||||
|       ++child; | ||||
|     } | ||||
| 
 | ||||
|     assert(child <= pq->max); | ||||
| 
 | ||||
|     hChild = n[child].handle; | ||||
|     if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { | ||||
|       n[curr].handle = hCurr; | ||||
|       h[hCurr].node = curr; | ||||
|       break; | ||||
|     } | ||||
|     n[curr].handle = hChild; | ||||
|     h[hChild].node = curr; | ||||
|     curr = child; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void FloatUp( PriorityQ *pq, long curr ) | ||||
| { | ||||
|   PQnode *n = pq->nodes; | ||||
|   PQhandleElem *h = pq->handles; | ||||
|   PQhandle hCurr, hParent; | ||||
|   long parent; | ||||
| 
 | ||||
|   hCurr = n[curr].handle; | ||||
|   for( ;; ) { | ||||
|     parent = curr >> 1; | ||||
|     hParent = n[parent].handle; | ||||
|     if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { | ||||
|       n[curr].handle = hCurr; | ||||
|       h[hCurr].node = curr; | ||||
|       break; | ||||
|     } | ||||
|     n[curr].handle = hParent; | ||||
|     h[hParent].node = curr; | ||||
|     curr = parent; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqHeapInit */ | ||||
| void pqInit( PriorityQ *pq ) | ||||
| { | ||||
|   long i; | ||||
| 
 | ||||
|   /* This method of building a heap is O(n), rather than O(n lg n). */ | ||||
| 
 | ||||
|   for( i = pq->size; i >= 1; --i ) { | ||||
|     FloatDown( pq, i ); | ||||
|   } | ||||
|   pq->initialized = TRUE; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqHeapInsert */ | ||||
| /* returns LONG_MAX iff out of memory */ | ||||
| PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) | ||||
| { | ||||
|   long curr; | ||||
|   PQhandle free_handle; | ||||
| 
 | ||||
|   curr = ++ pq->size; | ||||
|   if( (curr*2) > pq->max ) { | ||||
|     PQnode *saveNodes= pq->nodes; | ||||
|     PQhandleElem *saveHandles= pq->handles; | ||||
| 
 | ||||
|     /* If the heap overflows, double its size. */ | ||||
|     pq->max <<= 1; | ||||
|     pq->nodes = (PQnode *)memRealloc( pq->nodes,  | ||||
| 				     (size_t)  | ||||
| 				     ((pq->max + 1) * sizeof( pq->nodes[0] ))); | ||||
|     if (pq->nodes == NULL) { | ||||
|        pq->nodes = saveNodes;	/* restore ptr to free upon return */ | ||||
|        return LONG_MAX; | ||||
|     } | ||||
|     pq->handles = (PQhandleElem *)memRealloc( pq->handles, | ||||
| 			                     (size_t) | ||||
| 			                      ((pq->max + 1) *  | ||||
| 					       sizeof( pq->handles[0] ))); | ||||
|     if (pq->handles == NULL) { | ||||
|        pq->handles = saveHandles; /* restore ptr to free upon return */ | ||||
|        return LONG_MAX; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if( pq->freeList == 0 ) { | ||||
|     free_handle = curr; | ||||
|   } else { | ||||
|     free_handle = pq->freeList; | ||||
|     pq->freeList = pq->handles[free_handle].node; | ||||
|   } | ||||
| 
 | ||||
|   pq->nodes[curr].handle = free_handle; | ||||
|   pq->handles[free_handle].node = curr; | ||||
|   pq->handles[free_handle].key = keyNew; | ||||
| 
 | ||||
|   if( pq->initialized ) { | ||||
|     FloatUp( pq, curr ); | ||||
|   } | ||||
|   assert(free_handle != LONG_MAX); | ||||
|   return free_handle; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqHeapExtractMin */ | ||||
| PQkey pqExtractMin( PriorityQ *pq ) | ||||
| { | ||||
|   PQnode *n = pq->nodes; | ||||
|   PQhandleElem *h = pq->handles; | ||||
|   PQhandle hMin = n[1].handle; | ||||
|   PQkey min = h[hMin].key; | ||||
| 
 | ||||
|   if( pq->size > 0 ) { | ||||
|     n[1].handle = n[pq->size].handle; | ||||
|     h[n[1].handle].node = 1; | ||||
| 
 | ||||
|     h[hMin].key = NULL; | ||||
|     h[hMin].node = pq->freeList; | ||||
|     pq->freeList = hMin; | ||||
| 
 | ||||
|     if( -- pq->size > 0 ) { | ||||
|       FloatDown( pq, 1 ); | ||||
|     } | ||||
|   } | ||||
|   return min; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqHeapDelete */ | ||||
| void pqDelete( PriorityQ *pq, PQhandle hCurr ) | ||||
| { | ||||
|   PQnode *n = pq->nodes; | ||||
|   PQhandleElem *h = pq->handles; | ||||
|   long curr; | ||||
| 
 | ||||
|   assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); | ||||
| 
 | ||||
|   curr = h[hCurr].node; | ||||
|   n[curr].handle = n[pq->size].handle; | ||||
|   h[n[curr].handle].node = curr; | ||||
| 
 | ||||
|   if( curr <= -- pq->size ) { | ||||
|     if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { | ||||
|       FloatDown( pq, curr ); | ||||
|     } else { | ||||
|       FloatUp( pq, curr ); | ||||
|     } | ||||
|   } | ||||
|   h[hCurr].key = NULL; | ||||
|   h[hCurr].node = pq->freeList; | ||||
|   pq->freeList = hCurr; | ||||
| } | ||||
							
								
								
									
										107
									
								
								src/glu-libtess/src/priorityq-heap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/glu-libtess/src/priorityq-heap.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __priorityq_heap_h_ | ||||
| #define __priorityq_heap_h_ | ||||
| 
 | ||||
| /* Use #define's so that another heap implementation can use this one */ | ||||
| 
 | ||||
| #define PQkey			PQHeapKey | ||||
| #define PQhandle		PQHeapHandle | ||||
| #define PriorityQ		PriorityQHeap | ||||
| 
 | ||||
| #define pqNewPriorityQ(leq)	__gl_pqHeapNewPriorityQ(leq) | ||||
| #define pqDeletePriorityQ(pq)	__gl_pqHeapDeletePriorityQ(pq) | ||||
| 
 | ||||
| /* The basic operations are insertion of a new key (pqInsert),
 | ||||
|  * and examination/extraction of a key whose value is minimum | ||||
|  * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete); | ||||
|  * for this purpose pqInsert returns a "handle" which is supplied | ||||
|  * as the argument. | ||||
|  * | ||||
|  * An initial heap may be created efficiently by calling pqInsert | ||||
|  * repeatedly, then calling pqInit.  In any case pqInit must be called | ||||
|  * before any operations other than pqInsert are used. | ||||
|  * | ||||
|  * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. | ||||
|  * This may also be tested with pqIsEmpty. | ||||
|  */ | ||||
| #define pqInit(pq)		__gl_pqHeapInit(pq) | ||||
| #define pqInsert(pq,key)	__gl_pqHeapInsert(pq,key) | ||||
| #define pqMinimum(pq)		__gl_pqHeapMinimum(pq) | ||||
| #define pqExtractMin(pq)	__gl_pqHeapExtractMin(pq) | ||||
| #define pqDelete(pq,handle)	__gl_pqHeapDelete(pq,handle) | ||||
| #define pqIsEmpty(pq)		__gl_pqHeapIsEmpty(pq) | ||||
| 
 | ||||
| 
 | ||||
| /* Since we support deletion the data structure is a little more
 | ||||
|  * complicated than an ordinary heap.  "nodes" is the heap itself; | ||||
|  * active nodes are stored in the range 1..pq->size.  When the | ||||
|  * heap exceeds its allocated size (pq->max), its size doubles. | ||||
|  * The children of node i are nodes 2i and 2i+1. | ||||
|  * | ||||
|  * Each node stores an index into an array "handles".  Each handle | ||||
|  * stores a key, plus a pointer back to the node which currently | ||||
|  * represents that key (ie. nodes[handles[i].node].handle == i). | ||||
|  */ | ||||
| 
 | ||||
| typedef void *PQkey; | ||||
| typedef long PQhandle; | ||||
| typedef struct PriorityQ PriorityQ; | ||||
| 
 | ||||
| typedef struct { PQhandle handle; } PQnode; | ||||
| typedef struct { PQkey key; PQhandle node; } PQhandleElem; | ||||
| 
 | ||||
| struct PriorityQ { | ||||
|   PQnode	*nodes; | ||||
|   PQhandleElem	*handles; | ||||
|   long		size, max; | ||||
|   PQhandle	freeList; | ||||
|   int		initialized; | ||||
|   int		(*leq)(PQkey key1, PQkey key2); | ||||
| }; | ||||
|    | ||||
| PriorityQ	*pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); | ||||
| void		pqDeletePriorityQ( PriorityQ *pq ); | ||||
| 
 | ||||
| void		pqInit( PriorityQ *pq ); | ||||
| PQhandle	pqInsert( PriorityQ *pq, PQkey key ); | ||||
| PQkey		pqExtractMin( PriorityQ *pq ); | ||||
| void		pqDelete( PriorityQ *pq, PQhandle handle ); | ||||
| 
 | ||||
| 
 | ||||
| #define __gl_pqHeapMinimum(pq)	((pq)->handles[(pq)->nodes[1].handle].key) | ||||
| #define __gl_pqHeapIsEmpty(pq)	((pq)->size == 0) | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										117
									
								
								src/glu-libtess/src/priorityq-sort.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/glu-libtess/src/priorityq-sort.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __priorityq_sort_h_ | ||||
| #define __priorityq_sort_h_ | ||||
| 
 | ||||
| #include "priorityq-heap.h" | ||||
| 
 | ||||
| #undef PQkey | ||||
| #undef PQhandle | ||||
| #undef PriorityQ | ||||
| #undef pqNewPriorityQ | ||||
| #undef pqDeletePriorityQ | ||||
| #undef pqInit | ||||
| #undef pqInsert | ||||
| #undef pqMinimum | ||||
| #undef pqExtractMin | ||||
| #undef pqDelete | ||||
| #undef pqIsEmpty | ||||
| 
 | ||||
| /* Use #define's so that another heap implementation can use this one */ | ||||
| 
 | ||||
| #define PQkey			PQSortKey | ||||
| #define PQhandle		PQSortHandle | ||||
| #define PriorityQ		PriorityQSort | ||||
| 
 | ||||
| #define pqNewPriorityQ(leq)	__gl_pqSortNewPriorityQ(leq) | ||||
| #define pqDeletePriorityQ(pq)	__gl_pqSortDeletePriorityQ(pq) | ||||
| 
 | ||||
| /* The basic operations are insertion of a new key (pqInsert),
 | ||||
|  * and examination/extraction of a key whose value is minimum | ||||
|  * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete); | ||||
|  * for this purpose pqInsert returns a "handle" which is supplied | ||||
|  * as the argument. | ||||
|  * | ||||
|  * An initial heap may be created efficiently by calling pqInsert | ||||
|  * repeatedly, then calling pqInit.  In any case pqInit must be called | ||||
|  * before any operations other than pqInsert are used. | ||||
|  * | ||||
|  * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. | ||||
|  * This may also be tested with pqIsEmpty. | ||||
|  */ | ||||
| #define pqInit(pq)		__gl_pqSortInit(pq) | ||||
| #define pqInsert(pq,key)	__gl_pqSortInsert(pq,key) | ||||
| #define pqMinimum(pq)		__gl_pqSortMinimum(pq) | ||||
| #define pqExtractMin(pq)	__gl_pqSortExtractMin(pq) | ||||
| #define pqDelete(pq,handle)	__gl_pqSortDelete(pq,handle) | ||||
| #define pqIsEmpty(pq)		__gl_pqSortIsEmpty(pq) | ||||
| 
 | ||||
| 
 | ||||
| /* Since we support deletion the data structure is a little more
 | ||||
|  * complicated than an ordinary heap.  "nodes" is the heap itself; | ||||
|  * active nodes are stored in the range 1..pq->size.  When the | ||||
|  * heap exceeds its allocated size (pq->max), its size doubles. | ||||
|  * The children of node i are nodes 2i and 2i+1. | ||||
|  * | ||||
|  * Each node stores an index into an array "handles".  Each handle | ||||
|  * stores a key, plus a pointer back to the node which currently | ||||
|  * represents that key (ie. nodes[handles[i].node].handle == i). | ||||
|  */ | ||||
| 
 | ||||
| typedef PQHeapKey PQkey; | ||||
| typedef PQHeapHandle PQhandle; | ||||
| typedef struct PriorityQ PriorityQ; | ||||
| 
 | ||||
| struct PriorityQ { | ||||
|   PriorityQHeap	*heap; | ||||
|   PQkey		*keys; | ||||
|   PQkey		**order; | ||||
|   PQhandle	size, max; | ||||
|   int		initialized; | ||||
|   int		(*leq)(PQkey key1, PQkey key2); | ||||
| }; | ||||
|    | ||||
| PriorityQ	*pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); | ||||
| void		pqDeletePriorityQ( PriorityQ *pq ); | ||||
| 
 | ||||
| int		pqInit( PriorityQ *pq ); | ||||
| PQhandle	pqInsert( PriorityQ *pq, PQkey key ); | ||||
| PQkey		pqExtractMin( PriorityQ *pq ); | ||||
| void		pqDelete( PriorityQ *pq, PQhandle handle ); | ||||
| 
 | ||||
| PQkey		pqMinimum( PriorityQ *pq ); | ||||
| int		pqIsEmpty( PriorityQ *pq ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										261
									
								
								src/glu-libtess/src/priorityq.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								src/glu-libtess/src/priorityq.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,261 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| #include <limits.h>		/* LONG_MAX */ | ||||
| #include "memalloc.h" | ||||
| 
 | ||||
| /* Include all the code for the regular heap-based queue here. */ | ||||
| 
 | ||||
| #include "priorityq-heap.c" | ||||
| 
 | ||||
| /* Now redefine all the function names to map to their "Sort" versions. */ | ||||
| 
 | ||||
| #include "priorityq-sort.h" | ||||
| 
 | ||||
| /* really __gl_pqSortNewPriorityQ */ | ||||
| PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) | ||||
| { | ||||
|   PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); | ||||
|   if (pq == NULL) return NULL; | ||||
| 
 | ||||
|   pq->heap = __gl_pqHeapNewPriorityQ( leq ); | ||||
|   if (pq->heap == NULL) { | ||||
|      memFree(pq); | ||||
|      return NULL; | ||||
|   } | ||||
| 
 | ||||
|   pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); | ||||
|   if (pq->keys == NULL) { | ||||
|      __gl_pqHeapDeletePriorityQ(pq->heap); | ||||
|      memFree(pq); | ||||
|      return NULL; | ||||
|   } | ||||
| 
 | ||||
|   pq->order = NULL; | ||||
|   pq->size = 0; | ||||
|   pq->max = INIT_SIZE; | ||||
|   pq->initialized = FALSE; | ||||
|   pq->leq = leq; | ||||
|   return pq; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortDeletePriorityQ */ | ||||
| void pqDeletePriorityQ( PriorityQ *pq ) | ||||
| { | ||||
|   assert(pq != NULL);  | ||||
|   if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap ); | ||||
|   if (pq->order != NULL) memFree( pq->order ); | ||||
|   if (pq->keys != NULL) memFree( pq->keys ); | ||||
|   memFree( pq ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #define LT(x,y)		(! LEQ(y,x)) | ||||
| #define GT(x,y)		(! LEQ(x,y)) | ||||
| #define Swap(a,b)	do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0) | ||||
| 
 | ||||
| /* really __gl_pqSortInit */ | ||||
| int pqInit( PriorityQ *pq ) | ||||
| { | ||||
|   PQkey **p, **r, **i, **j, *piv; | ||||
|   struct { PQkey **p, **r; } Stack[50], *top = Stack; | ||||
|   unsigned long seed = 2016473283; | ||||
| 
 | ||||
|   /* Create an array of indirect pointers to the keys, so that we
 | ||||
|    * the handles we have returned are still valid. | ||||
|    */ | ||||
| /*
 | ||||
|   pq->order = (PQHeapKey **)memAlloc( (size_t) | ||||
|                                   (pq->size * sizeof(pq->order[0])) ); | ||||
| */ | ||||
|   pq->order = (PQHeapKey **)memAlloc( (size_t) | ||||
|                                   ((pq->size+1) * sizeof(pq->order[0])) ); | ||||
| /* the previous line is a patch to compensate for the fact that IBM */ | ||||
| /* machines return a null on a malloc of zero bytes (unlike SGI),   */ | ||||
| /* so we have to put in this defense to guard against a memory      */ | ||||
| /* fault four lines down. from fossum@austin.ibm.com.               */ | ||||
|   if (pq->order == NULL) return 0; | ||||
| 
 | ||||
|   p = pq->order; | ||||
|   r = p + pq->size - 1; | ||||
|   for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { | ||||
|     *i = piv; | ||||
|   } | ||||
| 
 | ||||
|   /* Sort the indirect pointers in descending order,
 | ||||
|    * using randomized Quicksort | ||||
|    */ | ||||
|   top->p = p; top->r = r; ++top; | ||||
|   while( --top >= Stack ) { | ||||
|     p = top->p; | ||||
|     r = top->r; | ||||
|     while( r > p + 10 ) { | ||||
|       seed = seed * 1539415821 + 1; | ||||
|       i = p + seed % (r - p + 1); | ||||
|       piv = *i; | ||||
|       *i = *p; | ||||
|       *p = piv; | ||||
|       i = p - 1; | ||||
|       j = r + 1; | ||||
|       do { | ||||
| 	do { ++i; } while( GT( **i, *piv )); | ||||
| 	do { --j; } while( LT( **j, *piv )); | ||||
| 	Swap( i, j ); | ||||
|       } while( i < j ); | ||||
|       Swap( i, j );	/* Undo last swap */ | ||||
|       if( i - p < r - j ) { | ||||
| 	top->p = j+1; top->r = r; ++top; | ||||
| 	r = i-1; | ||||
|       } else { | ||||
| 	top->p = p; top->r = i-1; ++top; | ||||
| 	p = j+1; | ||||
|       } | ||||
|     } | ||||
|     /* Insertion sort small lists */ | ||||
|     for( i = p+1; i <= r; ++i ) { | ||||
|       piv = *i; | ||||
|       for( j = i; j > p && LT( **(j-1), *piv ); --j ) { | ||||
| 	*j = *(j-1); | ||||
|       } | ||||
|       *j = piv; | ||||
|     } | ||||
|   } | ||||
|   pq->max = pq->size; | ||||
|   pq->initialized = TRUE; | ||||
|   __gl_pqHeapInit( pq->heap );	/* always succeeds */ | ||||
| 
 | ||||
| #ifndef NDEBUG | ||||
|   p = pq->order; | ||||
|   r = p + pq->size - 1; | ||||
|   for( i = p; i < r; ++i ) { | ||||
|     assert( LEQ( **(i+1), **i )); | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortInsert */ | ||||
| /* returns LONG_MAX iff out of memory */  | ||||
| PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) | ||||
| { | ||||
|   long curr; | ||||
| 
 | ||||
|   if( pq->initialized ) { | ||||
|     return __gl_pqHeapInsert( pq->heap, keyNew ); | ||||
|   } | ||||
|   curr = pq->size; | ||||
|   if( ++ pq->size >= pq->max ) { | ||||
|     PQkey *saveKey= pq->keys; | ||||
| 
 | ||||
|     /* If the heap overflows, double its size. */ | ||||
|     pq->max <<= 1; | ||||
|     pq->keys = (PQHeapKey *)memRealloc( pq->keys,  | ||||
| 	 	                        (size_t) | ||||
| 	                                 (pq->max * sizeof( pq->keys[0] ))); | ||||
|     if (pq->keys == NULL) {	 | ||||
|        pq->keys = saveKey;	/* restore ptr to free upon return */ | ||||
|        return LONG_MAX; | ||||
|     } | ||||
|   } | ||||
|   assert(curr != LONG_MAX);	 | ||||
|   pq->keys[curr] = keyNew; | ||||
| 
 | ||||
|   /* Negative handles index the sorted array. */ | ||||
|   return -(curr+1); | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortExtractMin */ | ||||
| PQkey pqExtractMin( PriorityQ *pq ) | ||||
| { | ||||
|   PQkey sortMin, heapMin; | ||||
| 
 | ||||
|   if( pq->size == 0 ) { | ||||
|     return __gl_pqHeapExtractMin( pq->heap ); | ||||
|   } | ||||
|   sortMin = *(pq->order[pq->size-1]); | ||||
|   if( ! __gl_pqHeapIsEmpty( pq->heap )) { | ||||
|     heapMin = __gl_pqHeapMinimum( pq->heap ); | ||||
|     if( LEQ( heapMin, sortMin )) { | ||||
|       return __gl_pqHeapExtractMin( pq->heap ); | ||||
|     } | ||||
|   } | ||||
|   do { | ||||
|     -- pq->size; | ||||
|   } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); | ||||
|   return sortMin; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortMinimum */ | ||||
| PQkey pqMinimum( PriorityQ *pq ) | ||||
| { | ||||
|   PQkey sortMin, heapMin; | ||||
| 
 | ||||
|   if( pq->size == 0 ) { | ||||
|     return __gl_pqHeapMinimum( pq->heap ); | ||||
|   } | ||||
|   sortMin = *(pq->order[pq->size-1]); | ||||
|   if( ! __gl_pqHeapIsEmpty( pq->heap )) { | ||||
|     heapMin = __gl_pqHeapMinimum( pq->heap ); | ||||
|     if( LEQ( heapMin, sortMin )) { | ||||
|       return heapMin; | ||||
|     } | ||||
|   } | ||||
|   return sortMin; | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortIsEmpty */ | ||||
| int pqIsEmpty( PriorityQ *pq ) | ||||
| { | ||||
|   return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap ); | ||||
| } | ||||
| 
 | ||||
| /* really __gl_pqSortDelete */ | ||||
| void pqDelete( PriorityQ *pq, PQhandle curr ) | ||||
| { | ||||
|   if( curr >= 0 ) { | ||||
|     __gl_pqHeapDelete( pq->heap, curr ); | ||||
|     return; | ||||
|   } | ||||
|   curr = -(curr+1); | ||||
|   assert( curr < pq->max && pq->keys[curr] != NULL ); | ||||
| 
 | ||||
|   pq->keys[curr] = NULL; | ||||
|   while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { | ||||
|     -- pq->size; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										117
									
								
								src/glu-libtess/src/priorityq.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/glu-libtess/src/priorityq.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __priorityq_sort_h_ | ||||
| #define __priorityq_sort_h_ | ||||
| 
 | ||||
| #include "priorityq-heap.h" | ||||
| 
 | ||||
| #undef PQkey | ||||
| #undef PQhandle | ||||
| #undef PriorityQ | ||||
| #undef pqNewPriorityQ | ||||
| #undef pqDeletePriorityQ | ||||
| #undef pqInit | ||||
| #undef pqInsert | ||||
| #undef pqMinimum | ||||
| #undef pqExtractMin | ||||
| #undef pqDelete | ||||
| #undef pqIsEmpty | ||||
| 
 | ||||
| /* Use #define's so that another heap implementation can use this one */ | ||||
| 
 | ||||
| #define PQkey			PQSortKey | ||||
| #define PQhandle		PQSortHandle | ||||
| #define PriorityQ		PriorityQSort | ||||
| 
 | ||||
| #define pqNewPriorityQ(leq)	__gl_pqSortNewPriorityQ(leq) | ||||
| #define pqDeletePriorityQ(pq)	__gl_pqSortDeletePriorityQ(pq) | ||||
| 
 | ||||
| /* The basic operations are insertion of a new key (pqInsert),
 | ||||
|  * and examination/extraction of a key whose value is minimum | ||||
|  * (pqMinimum/pqExtractMin).  Deletion is also allowed (pqDelete); | ||||
|  * for this purpose pqInsert returns a "handle" which is supplied | ||||
|  * as the argument. | ||||
|  * | ||||
|  * An initial heap may be created efficiently by calling pqInsert | ||||
|  * repeatedly, then calling pqInit.  In any case pqInit must be called | ||||
|  * before any operations other than pqInsert are used. | ||||
|  * | ||||
|  * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. | ||||
|  * This may also be tested with pqIsEmpty. | ||||
|  */ | ||||
| #define pqInit(pq)		__gl_pqSortInit(pq) | ||||
| #define pqInsert(pq,key)	__gl_pqSortInsert(pq,key) | ||||
| #define pqMinimum(pq)		__gl_pqSortMinimum(pq) | ||||
| #define pqExtractMin(pq)	__gl_pqSortExtractMin(pq) | ||||
| #define pqDelete(pq,handle)	__gl_pqSortDelete(pq,handle) | ||||
| #define pqIsEmpty(pq)		__gl_pqSortIsEmpty(pq) | ||||
| 
 | ||||
| 
 | ||||
| /* Since we support deletion the data structure is a little more
 | ||||
|  * complicated than an ordinary heap.  "nodes" is the heap itself; | ||||
|  * active nodes are stored in the range 1..pq->size.  When the | ||||
|  * heap exceeds its allocated size (pq->max), its size doubles. | ||||
|  * The children of node i are nodes 2i and 2i+1. | ||||
|  * | ||||
|  * Each node stores an index into an array "handles".  Each handle | ||||
|  * stores a key, plus a pointer back to the node which currently | ||||
|  * represents that key (ie. nodes[handles[i].node].handle == i). | ||||
|  */ | ||||
| 
 | ||||
| typedef PQHeapKey PQkey; | ||||
| typedef PQHeapHandle PQhandle; | ||||
| typedef struct PriorityQ PriorityQ; | ||||
| 
 | ||||
| struct PriorityQ { | ||||
|   PriorityQHeap	*heap; | ||||
|   PQkey		*keys; | ||||
|   PQkey		**order; | ||||
|   PQhandle	size, max; | ||||
|   int		initialized; | ||||
|   int		(*leq)(PQkey key1, PQkey key2); | ||||
| }; | ||||
|    | ||||
| PriorityQ	*pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); | ||||
| void		pqDeletePriorityQ( PriorityQ *pq ); | ||||
| 
 | ||||
| int		pqInit( PriorityQ *pq ); | ||||
| PQhandle	pqInsert( PriorityQ *pq, PQkey key ); | ||||
| PQkey		pqExtractMin( PriorityQ *pq ); | ||||
| void		pqDelete( PriorityQ *pq, PQhandle handle ); | ||||
| 
 | ||||
| PQkey		pqMinimum( PriorityQ *pq ); | ||||
| int		pqIsEmpty( PriorityQ *pq ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										502
									
								
								src/glu-libtess/src/render.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								src/glu-libtess/src/render.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,502 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <assert.h> | ||||
| #include <stddef.h> | ||||
| #include "mesh.h" | ||||
| #include "tess.h" | ||||
| #include "render.h" | ||||
| 
 | ||||
| #ifndef TRUE | ||||
| #define TRUE 1 | ||||
| #endif | ||||
| #ifndef FALSE | ||||
| #define FALSE 0 | ||||
| #endif | ||||
| 
 | ||||
| /* This structure remembers the information we need about a primitive
 | ||||
|  * to be able to render it later, once we have determined which | ||||
|  * primitive is able to use the most triangles. | ||||
|  */ | ||||
| struct FaceCount { | ||||
|   long		size;		/* number of triangles used */ | ||||
|   GLUhalfEdge	*eStart;	/* edge where this primitive starts */ | ||||
|   void		(*render)(GLUtesselator *, GLUhalfEdge *, long); | ||||
|                                 /* routine to render this primitive */ | ||||
| }; | ||||
| 
 | ||||
| static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ); | ||||
| static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ); | ||||
| 
 | ||||
| static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); | ||||
| static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); | ||||
| static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart, | ||||
| 			    long size ); | ||||
| 
 | ||||
| static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ); | ||||
| static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head ); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /************************ Strips and Fans decomposition ******************/ | ||||
| 
 | ||||
| /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
 | ||||
|  * fans, strips, and separate triangles.  A substantial effort is made | ||||
|  * to use as few rendering primitives as possible (ie. to make the fans | ||||
|  * and strips as large as possible). | ||||
|  * | ||||
|  * The rendering output is provided as callbacks (see the api). | ||||
|  */ | ||||
| void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *f; | ||||
| 
 | ||||
|   /* Make a list of separate triangles so we can render them all at once */ | ||||
|   tess->lonelyTriList = NULL; | ||||
| 
 | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { | ||||
|     f->marked = FALSE; | ||||
|   } | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { | ||||
| 
 | ||||
|     /* We examine all faces in an arbitrary order.  Whenever we find
 | ||||
|      * an unprocessed face F, we output a group of faces including F | ||||
|      * whose size is maximum. | ||||
|      */ | ||||
|     if( f->inside && ! f->marked ) { | ||||
|       RenderMaximumFaceGroup( tess, f ); | ||||
|       assert( f->marked ); | ||||
|     } | ||||
|   } | ||||
|   if( tess->lonelyTriList != NULL ) { | ||||
|     RenderLonelyTriangles( tess, tess->lonelyTriList ); | ||||
|     tess->lonelyTriList = NULL; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ) | ||||
| { | ||||
|   /* We want to find the largest triangle fan or strip of unmarked faces
 | ||||
|    * which includes the given face fOrig.  There are 3 possible fans | ||||
|    * passing through fOrig (one centered at each vertex), and 3 possible | ||||
|    * strips (one for each CCW permutation of the vertices).  Our strategy | ||||
|    * is to try all of these, and take the primitive which uses the most | ||||
|    * triangles (a greedy approach). | ||||
|    */ | ||||
|   GLUhalfEdge *e = fOrig->anEdge; | ||||
|   struct FaceCount max, newFace; | ||||
| 
 | ||||
|   max.size = 1; | ||||
|   max.eStart = e; | ||||
|   max.render = &RenderTriangle; | ||||
| 
 | ||||
|   if( ! tess->flagBoundary ) { | ||||
|     newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; } | ||||
|     newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } | ||||
|     newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } | ||||
| 
 | ||||
|     newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; } | ||||
|     newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } | ||||
|     newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } | ||||
|   } | ||||
|   (*(max.render))( tess, max.eStart, max.size ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Macros which keep track of faces we have marked temporarily, and allow
 | ||||
|  * us to backtrack when necessary.  With triangle fans, this is not | ||||
|  * really necessary, since the only awkward case is a loop of triangles | ||||
|  * around a single origin vertex.  However with strips the situation is | ||||
|  * more complicated, and we need a general tracking method like the | ||||
|  * one here. | ||||
|  */ | ||||
| #define Marked(f)	(! (f)->inside || (f)->marked) | ||||
| 
 | ||||
| #define AddToTrail(f,t)	((f)->trail = (t), (t) = (f), (f)->marked = TRUE) | ||||
| 
 | ||||
| #define FreeTrail(t)	do { \ | ||||
| 			  while( (t) != NULL ) { \ | ||||
| 			    (t)->marked = FALSE; t = (t)->trail; \ | ||||
| 			  } \ | ||||
| 			} while(0) /* absorb trailing semicolon */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ) | ||||
| { | ||||
|   /* eOrig->Lface is the face we want to render.  We want to find the size
 | ||||
|    * of a maximal fan around eOrig->Org.  To do this we just walk around | ||||
|    * the origin vertex as far as possible in both directions. | ||||
|    */ | ||||
|   struct FaceCount newFace = { 0, NULL, &RenderFan }; | ||||
|   GLUface *trail = NULL; | ||||
|   GLUhalfEdge *e; | ||||
| 
 | ||||
|   for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) { | ||||
|     AddToTrail( e->Lface, trail ); | ||||
|     ++newFace.size; | ||||
|   } | ||||
|   for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) { | ||||
|     AddToTrail( e->Rface, trail ); | ||||
|     ++newFace.size; | ||||
|   } | ||||
|   newFace.eStart = e; | ||||
|   /*LINTED*/ | ||||
|   FreeTrail( trail ); | ||||
|   return newFace; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #define IsEven(n)	(((n) & 1) == 0) | ||||
| 
 | ||||
| static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ) | ||||
| { | ||||
|   /* Here we are looking for a maximal strip that contains the vertices
 | ||||
|    * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the | ||||
|    * reverse, such that all triangles are oriented CCW). | ||||
|    * | ||||
|    * Again we walk forward and backward as far as possible.  However for | ||||
|    * strips there is a twist: to get CCW orientations, there must be | ||||
|    * an *even* number of triangles in the strip on one side of eOrig. | ||||
|    * We walk the strip starting on a side with an even number of triangles; | ||||
|    * if both side have an odd number, we are forced to shorten one side. | ||||
|    */ | ||||
|   struct FaceCount newFace = { 0, NULL, &RenderStrip }; | ||||
|   long headSize = 0, tailSize = 0; | ||||
|   GLUface *trail = NULL; | ||||
|   GLUhalfEdge *e, *eTail, *eHead; | ||||
| 
 | ||||
|   for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) { | ||||
|     AddToTrail( e->Lface, trail ); | ||||
|     ++tailSize; | ||||
|     e = e->Dprev; | ||||
|     if( Marked( e->Lface )) break; | ||||
|     AddToTrail( e->Lface, trail ); | ||||
|   } | ||||
|   eTail = e; | ||||
| 
 | ||||
|   for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) { | ||||
|     AddToTrail( e->Rface, trail ); | ||||
|     ++headSize; | ||||
|     e = e->Oprev; | ||||
|     if( Marked( e->Rface )) break; | ||||
|     AddToTrail( e->Rface, trail ); | ||||
|   } | ||||
|   eHead = e; | ||||
| 
 | ||||
|   newFace.size = tailSize + headSize; | ||||
|   if( IsEven( tailSize )) { | ||||
|     newFace.eStart = eTail->Sym; | ||||
|   } else if( IsEven( headSize )) { | ||||
|     newFace.eStart = eHead; | ||||
|   } else { | ||||
|     /* Both sides have odd length, we must shorten one of them.  In fact,
 | ||||
|      * we must start from eHead to guarantee inclusion of eOrig->Lface. | ||||
|      */ | ||||
|     --newFace.size; | ||||
|     newFace.eStart = eHead->Onext; | ||||
|   } | ||||
|   /*LINTED*/ | ||||
|   FreeTrail( trail ); | ||||
|   return newFace; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size ) | ||||
| { | ||||
|   /* Just add the triangle to a triangle list, so we can render all
 | ||||
|    * the separate triangles at once. | ||||
|    */ | ||||
|   assert( size == 1 ); | ||||
|   AddToTrail( e->Lface, tess->lonelyTriList ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f ) | ||||
| { | ||||
|   /* Now we render all the separate triangles which could not be
 | ||||
|    * grouped into a triangle fan or strip. | ||||
|    */ | ||||
|   GLUhalfEdge *e; | ||||
|   int newState; | ||||
|   int edgeState = -1;	/* force edge state output for first vertex */ | ||||
| 
 | ||||
|   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); | ||||
| 
 | ||||
|   for( ; f != NULL; f = f->trail ) { | ||||
|     /* Loop once for each edge (there will always be 3 edges) */ | ||||
| 
 | ||||
|     e = f->anEdge; | ||||
|     do { | ||||
|       if( tess->flagBoundary ) { | ||||
| 	/* Set the "edge state" to TRUE just before we output the
 | ||||
| 	 * first vertex of each edge on the polygon boundary. | ||||
| 	 */ | ||||
| 	newState = ! e->Rface->inside; | ||||
| 	if( edgeState != newState ) { | ||||
| 	  edgeState = newState; | ||||
|           CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); | ||||
| 	} | ||||
|       } | ||||
|       CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); | ||||
| 
 | ||||
|       e = e->Lnext; | ||||
|     } while( e != f->anEdge ); | ||||
|   } | ||||
|   CALL_END_OR_END_DATA(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ) | ||||
| { | ||||
|   /* Render as many CCW triangles as possible in a fan starting from
 | ||||
|    * edge "e".  The fan *should* contain exactly "size" triangles | ||||
|    * (otherwise we've goofed up somewhere). | ||||
|    */ | ||||
|   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );  | ||||
|   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );  | ||||
|   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );  | ||||
| 
 | ||||
|   while( ! Marked( e->Lface )) { | ||||
|     e->Lface->marked = TRUE; | ||||
|     --size; | ||||
|     e = e->Onext; | ||||
|     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );  | ||||
|   } | ||||
| 
 | ||||
|   assert( size == 0 ); | ||||
|   CALL_END_OR_END_DATA(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ) | ||||
| { | ||||
|   /* Render as many CCW triangles as possible in a strip starting from
 | ||||
|    * edge "e".  The strip *should* contain exactly "size" triangles | ||||
|    * (otherwise we've goofed up somewhere). | ||||
|    */ | ||||
|   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); | ||||
|   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );  | ||||
|   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );  | ||||
| 
 | ||||
|   while( ! Marked( e->Lface )) { | ||||
|     e->Lface->marked = TRUE; | ||||
|     --size; | ||||
|     e = e->Dprev; | ||||
|     CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );  | ||||
|     if( Marked( e->Lface )) break; | ||||
| 
 | ||||
|     e->Lface->marked = TRUE; | ||||
|     --size; | ||||
|     e = e->Onext; | ||||
|     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );  | ||||
|   } | ||||
| 
 | ||||
|   assert( size == 0 ); | ||||
|   CALL_END_OR_END_DATA(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /************************ Boundary contour decomposition ******************/ | ||||
| 
 | ||||
| /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
 | ||||
|  * contour for each face marked "inside".  The rendering output is | ||||
|  * provided as callbacks (see the api). | ||||
|  */ | ||||
| void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *f; | ||||
|   GLUhalfEdge *e; | ||||
| 
 | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { | ||||
|     if( f->inside ) { | ||||
|       CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); | ||||
|       e = f->anEdge; | ||||
|       do { | ||||
|         CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );  | ||||
| 	e = e->Lnext; | ||||
|       } while( e != f->anEdge ); | ||||
|       CALL_END_OR_END_DATA(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /************************ Quick-and-dirty decomposition ******************/ | ||||
| 
 | ||||
| #define SIGN_INCONSISTENT 2 | ||||
| 
 | ||||
| static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check ) | ||||
| /*
 | ||||
|  * If check==FALSE, we compute the polygon normal and place it in norm[]. | ||||
|  * If check==TRUE, we check that each triangle in the fan from v0 has a | ||||
|  * consistent orientation with respect to norm[].  If triangles are | ||||
|  * consistently oriented CCW, return 1; if CW, return -1; if all triangles | ||||
|  * are degenerate return 0; otherwise (no consistent orientation) return | ||||
|  * SIGN_INCONSISTENT. | ||||
|  */ | ||||
| { | ||||
|   CachedVertex *v0 = tess->cache; | ||||
|   CachedVertex *vn = v0 + tess->cacheCount; | ||||
|   CachedVertex *vc; | ||||
|   GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; | ||||
|   int sign = 0; | ||||
| 
 | ||||
|   /* Find the polygon normal.  It is important to get a reasonable
 | ||||
|    * normal even when the polygon is self-intersecting (eg. a bowtie). | ||||
|    * Otherwise, the computed normal could be very tiny, but perpendicular | ||||
|    * to the true plane of the polygon due to numerical noise.  Then all | ||||
|    * the triangles would appear to be degenerate and we would incorrectly | ||||
|    * decompose the polygon as a fan (or simply not render it at all). | ||||
|    * | ||||
|    * We use a sum-of-triangles normal algorithm rather than the more | ||||
|    * efficient sum-of-trapezoids method (used in CheckOrientation() | ||||
|    * in normal.c).  This lets us explicitly reverse the signed area | ||||
|    * of some triangles to get a reasonable normal in the self-intersecting | ||||
|    * case. | ||||
|    */ | ||||
|   if( ! check ) { | ||||
|     norm[0] = norm[1] = norm[2] = 0.0; | ||||
|   } | ||||
| 
 | ||||
|   vc = v0 + 1; | ||||
|   xc = vc->coords[0] - v0->coords[0]; | ||||
|   yc = vc->coords[1] - v0->coords[1]; | ||||
|   zc = vc->coords[2] - v0->coords[2]; | ||||
|   while( ++vc < vn ) { | ||||
|     xp = xc; yp = yc; zp = zc; | ||||
|     xc = vc->coords[0] - v0->coords[0]; | ||||
|     yc = vc->coords[1] - v0->coords[1]; | ||||
|     zc = vc->coords[2] - v0->coords[2]; | ||||
| 
 | ||||
|     /* Compute (vp - v0) cross (vc - v0) */ | ||||
|     n[0] = yp*zc - zp*yc; | ||||
|     n[1] = zp*xc - xp*zc; | ||||
|     n[2] = xp*yc - yp*xc; | ||||
| 
 | ||||
|     dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; | ||||
|     if( ! check ) { | ||||
|       /* Reverse the contribution of back-facing triangles to get
 | ||||
|        * a reasonable normal for self-intersecting polygons (see above) | ||||
|        */ | ||||
|       if( dot >= 0 ) { | ||||
| 	norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; | ||||
|       } else { | ||||
| 	norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; | ||||
|       } | ||||
|     } else if( dot != 0 ) { | ||||
|       /* Check the new orientation for consistency with previous triangles */ | ||||
|       if( dot > 0 ) { | ||||
| 	if( sign < 0 ) return SIGN_INCONSISTENT; | ||||
| 	sign = 1; | ||||
|       } else { | ||||
| 	if( sign > 0 ) return SIGN_INCONSISTENT; | ||||
| 	sign = -1; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return sign; | ||||
| } | ||||
| 
 | ||||
| /* __gl_renderCache( tess ) takes a single contour and tries to render it
 | ||||
|  * as a triangle fan.  This handles convex polygons, as well as some | ||||
|  * non-convex polygons if we get lucky. | ||||
|  * | ||||
|  * Returns TRUE if the polygon was successfully rendered.  The rendering | ||||
|  * output is provided as callbacks (see the api). | ||||
|  */ | ||||
| GLboolean __gl_renderCache( GLUtesselator *tess ) | ||||
| { | ||||
|   CachedVertex *v0 = tess->cache; | ||||
|   CachedVertex *vn = v0 + tess->cacheCount; | ||||
|   CachedVertex *vc; | ||||
|   GLdouble norm[3]; | ||||
|   int sign; | ||||
| 
 | ||||
|   if( tess->cacheCount < 3 ) { | ||||
|     /* Degenerate contour -- no output */ | ||||
|     return TRUE; | ||||
|   } | ||||
| 
 | ||||
|   norm[0] = tess->normal[0]; | ||||
|   norm[1] = tess->normal[1]; | ||||
|   norm[2] = tess->normal[2]; | ||||
|   if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { | ||||
|     ComputeNormal( tess, norm, FALSE ); | ||||
|   } | ||||
| 
 | ||||
|   sign = ComputeNormal( tess, norm, TRUE ); | ||||
|   if( sign == SIGN_INCONSISTENT ) { | ||||
|     /* Fan triangles did not have a consistent orientation */ | ||||
|     return FALSE; | ||||
|   } | ||||
|   if( sign == 0 ) { | ||||
|     /* All triangles were degenerate */ | ||||
|     return TRUE; | ||||
|   } | ||||
| 
 | ||||
|   /* Make sure we do the right thing for each winding rule */ | ||||
|   switch( tess->windingRule ) { | ||||
|   case GLU_TESS_WINDING_ODD: | ||||
|   case GLU_TESS_WINDING_NONZERO: | ||||
|     break; | ||||
|   case GLU_TESS_WINDING_POSITIVE: | ||||
|     if( sign < 0 ) return TRUE; | ||||
|     break; | ||||
|   case GLU_TESS_WINDING_NEGATIVE: | ||||
|     if( sign > 0 ) return TRUE; | ||||
|     break; | ||||
|   case GLU_TESS_WINDING_ABS_GEQ_TWO: | ||||
|     return TRUE; | ||||
|   } | ||||
| 
 | ||||
|   CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP | ||||
| 			  : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN | ||||
| 			  : GL_TRIANGLES ); | ||||
| 
 | ||||
|   CALL_VERTEX_OR_VERTEX_DATA( v0->data );  | ||||
|   if( sign > 0 ) { | ||||
|     for( vc = v0+1; vc < vn; ++vc ) { | ||||
|       CALL_VERTEX_OR_VERTEX_DATA( vc->data );  | ||||
|     } | ||||
|   } else { | ||||
|     for( vc = vn-1; vc > v0; --vc ) { | ||||
|       CALL_VERTEX_OR_VERTEX_DATA( vc->data );  | ||||
|     } | ||||
|   } | ||||
|   CALL_END_OR_END_DATA(); | ||||
|   return TRUE; | ||||
| } | ||||
							
								
								
									
										52
									
								
								src/glu-libtess/src/render.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/glu-libtess/src/render.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __render_h_ | ||||
| #define __render_h_ | ||||
| 
 | ||||
| #include "mesh.h" | ||||
| 
 | ||||
| /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
 | ||||
|  * fans, strips, and separate triangles.  A substantial effort is made | ||||
|  * to use as few rendering primitives as possible (ie. to make the fans | ||||
|  * and strips as large as possible). | ||||
|  * | ||||
|  * The rendering output is provided as callbacks (see the api). | ||||
|  */ | ||||
| void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ); | ||||
| void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ); | ||||
| 
 | ||||
| GLboolean __gl_renderCache( GLUtesselator *tess ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										1361
									
								
								src/glu-libtess/src/sweep.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1361
									
								
								src/glu-libtess/src/sweep.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										77
									
								
								src/glu-libtess/src/sweep.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/glu-libtess/src/sweep.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __sweep_h_ | ||||
| #define __sweep_h_ | ||||
| 
 | ||||
| #include "mesh.h" | ||||
| 
 | ||||
| /* __gl_computeInterior( tess ) computes the planar arrangement specified
 | ||||
|  * by the given contours, and further subdivides this arrangement | ||||
|  * into regions.  Each region is marked "inside" if it belongs | ||||
|  * to the polygon, according to the rule given by tess->windingRule. | ||||
|  * Each interior region is guaranteed be monotone. | ||||
|  */ | ||||
| int __gl_computeInterior( GLUtesselator *tess ); | ||||
| 
 | ||||
| 
 | ||||
| /* The following is here *only* for access by debugging routines */ | ||||
| 
 | ||||
| #include "dict.h" | ||||
| 
 | ||||
| /* For each pair of adjacent edges crossing the sweep line, there is
 | ||||
|  * an ActiveRegion to represent the region between them.  The active | ||||
|  * regions are kept in sorted order in a dynamic dictionary.  As the | ||||
|  * sweep line crosses each vertex, we update the affected regions. | ||||
|  */ | ||||
| 
 | ||||
| struct ActiveRegion { | ||||
|   GLUhalfEdge	*eUp;		/* upper edge, directed right to left */ | ||||
|   DictNode	*nodeUp;	/* dictionary node corresponding to eUp */ | ||||
|   int		windingNumber;	/* used to determine which regions are
 | ||||
|                                  * inside the polygon */ | ||||
|   GLboolean	inside;		/* is this region inside the polygon? */ | ||||
|   GLboolean	sentinel;	/* marks fake edges at t = +/-infinity */ | ||||
|   GLboolean	dirty;		/* marks regions where the upper or lower
 | ||||
|                                  * edge has changed, but we haven't checked | ||||
|                                  * whether they intersect yet */ | ||||
|   GLboolean	fixUpperEdge;	/* marks temporary edges introduced when
 | ||||
|                                  * we process a "right vertex" (one without | ||||
|                                  * any edges leaving to the right) */ | ||||
| }; | ||||
| 
 | ||||
| #define RegionBelow(r)	((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) | ||||
| #define RegionAbove(r)	((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										632
									
								
								src/glu-libtess/src/tess.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										632
									
								
								src/glu-libtess/src/tess.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,632 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| #include <setjmp.h> | ||||
| #include "memalloc.h" | ||||
| #include "tess.h" | ||||
| #include "mesh.h" | ||||
| #include "normal.h" | ||||
| #include "sweep.h" | ||||
| #include "tessmono.h" | ||||
| #include "render.h" | ||||
| 
 | ||||
| #define GLU_TESS_DEFAULT_TOLERANCE 0.0 | ||||
| #define GLU_TESS_MESH		100112	/* void (*)(GLUmesh *mesh)	    */ | ||||
| 
 | ||||
| #ifndef TRUE | ||||
| #define TRUE 1 | ||||
| #endif | ||||
| #ifndef FALSE | ||||
| #define FALSE 0 | ||||
| #endif | ||||
| 
 | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], | ||||
| 				    GLfloat weight[4], void **dataOut ) {} | ||||
| /*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} | ||||
| 
 | ||||
| 
 | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, | ||||
| 					     void *polygonData ) {} | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, | ||||
| 				       void *polygonData ) {} | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, | ||||
| 					      void *polygonData ) {} | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, | ||||
| 					     void *polygonData ) {} | ||||
| /*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], | ||||
| 					       void *data[4], | ||||
| 					       GLfloat weight[4], | ||||
| 					       void **outData, | ||||
| 					       void *polygonData ) {} | ||||
| 
 | ||||
| /* Half-edges are allocated in pairs (see mesh.c) */ | ||||
| typedef struct { GLUhalfEdge e, eSym; } EdgePair; | ||||
| 
 | ||||
| #undef	MAX | ||||
| #define MAX(a,b)	((a) > (b) ? (a) : (b)) | ||||
| #define MAX_FAST_ALLOC	(MAX(sizeof(EdgePair), \ | ||||
|                          MAX(sizeof(GLUvertex),sizeof(GLUface)))) | ||||
| 
 | ||||
| 
 | ||||
| GLUtesselator * GLAPIENTRY | ||||
| gluNewTess( void ) | ||||
| { | ||||
|   GLUtesselator *tess; | ||||
| 
 | ||||
|   /* Only initialize fields which can be changed by the api.  Other fields
 | ||||
|    * are initialized where they are used. | ||||
|    */ | ||||
| 
 | ||||
|   if (memInit( MAX_FAST_ALLOC ) == 0) { | ||||
|      return 0;			/* out of memory */ | ||||
|   } | ||||
|   tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); | ||||
|   if (tess == NULL) { | ||||
|      return 0;			/* out of memory */ | ||||
|   } | ||||
| 
 | ||||
|   tess->state = T_DORMANT; | ||||
| 
 | ||||
|   tess->normal[0] = 0; | ||||
|   tess->normal[1] = 0; | ||||
|   tess->normal[2] = 0; | ||||
| 
 | ||||
|   tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; | ||||
|   tess->windingRule = GLU_TESS_WINDING_ODD; | ||||
|   tess->flagBoundary = FALSE; | ||||
|   tess->boundaryOnly = FALSE; | ||||
| 
 | ||||
|   tess->callBegin = &noBegin; | ||||
|   tess->callEdgeFlag = &noEdgeFlag; | ||||
|   tess->callVertex = &noVertex; | ||||
|   tess->callEnd = &noEnd; | ||||
| 
 | ||||
|   tess->callError = &noError; | ||||
|   tess->callCombine = &noCombine; | ||||
|   tess->callMesh = &noMesh; | ||||
| 
 | ||||
|   tess->callBeginData= &__gl_noBeginData; | ||||
|   tess->callEdgeFlagData= &__gl_noEdgeFlagData; | ||||
|   tess->callVertexData= &__gl_noVertexData; | ||||
|   tess->callEndData= &__gl_noEndData; | ||||
|   tess->callErrorData= &__gl_noErrorData; | ||||
|   tess->callCombineData= &__gl_noCombineData; | ||||
| 
 | ||||
|   tess->polygonData= NULL; | ||||
| 
 | ||||
|   return tess; | ||||
| } | ||||
| 
 | ||||
| static void MakeDormant( GLUtesselator *tess ) | ||||
| { | ||||
|   /* Return the tessellator to its original dormant state. */ | ||||
| 
 | ||||
|   if( tess->mesh != NULL ) { | ||||
|     __gl_meshDeleteMesh( tess->mesh ); | ||||
|   } | ||||
|   tess->state = T_DORMANT; | ||||
|   tess->lastEdge = NULL; | ||||
|   tess->mesh = NULL; | ||||
| } | ||||
| 
 | ||||
| #define RequireState( tess, s )   if( tess->state != s ) GotoState(tess,s) | ||||
| 
 | ||||
| static void GotoState( GLUtesselator *tess, enum TessState newState ) | ||||
| { | ||||
|   while( tess->state != newState ) { | ||||
|     /* We change the current state one level at a time, to get to
 | ||||
|      * the desired state. | ||||
|      */ | ||||
|     if( tess->state < newState ) { | ||||
|       switch( tess->state ) { | ||||
|       case T_DORMANT: | ||||
| 	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); | ||||
| 	gluTessBeginPolygon( tess, NULL ); | ||||
| 	break; | ||||
|       case T_IN_POLYGON: | ||||
| 	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); | ||||
| 	gluTessBeginContour( tess ); | ||||
| 	break; | ||||
|       default: | ||||
| 	 ; | ||||
|       } | ||||
|     } else { | ||||
|       switch( tess->state ) { | ||||
|       case T_IN_CONTOUR: | ||||
| 	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); | ||||
| 	gluTessEndContour( tess ); | ||||
| 	break; | ||||
|       case T_IN_POLYGON: | ||||
| 	CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); | ||||
| 	/* gluTessEndPolygon( tess ) is too much work! */ | ||||
| 	MakeDormant( tess ); | ||||
| 	break; | ||||
|       default: | ||||
| 	 ; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluDeleteTess( GLUtesselator *tess ) | ||||
| { | ||||
|   RequireState( tess, T_DORMANT ); | ||||
|   memFree( tess ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) | ||||
| { | ||||
|   GLenum windingRule; | ||||
| 
 | ||||
|   switch( which ) { | ||||
|   case GLU_TESS_TOLERANCE: | ||||
|     if( value < 0.0 || value > 1.0 ) break; | ||||
|     tess->relTolerance = value; | ||||
|     return; | ||||
| 
 | ||||
|   case GLU_TESS_WINDING_RULE: | ||||
|     windingRule = (GLenum) value; | ||||
|     if( windingRule != value ) break;	/* not an integer */ | ||||
| 
 | ||||
|     switch( windingRule ) { | ||||
|     case GLU_TESS_WINDING_ODD: | ||||
|     case GLU_TESS_WINDING_NONZERO: | ||||
|     case GLU_TESS_WINDING_POSITIVE: | ||||
|     case GLU_TESS_WINDING_NEGATIVE: | ||||
|     case GLU_TESS_WINDING_ABS_GEQ_TWO: | ||||
|       tess->windingRule = windingRule; | ||||
|       return; | ||||
|     default: | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   case GLU_TESS_BOUNDARY_ONLY: | ||||
|     tess->boundaryOnly = (value != 0); | ||||
|     return; | ||||
| 
 | ||||
|   default: | ||||
|     CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); | ||||
|     return; | ||||
|   } | ||||
|   CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); | ||||
| } | ||||
| 
 | ||||
| /* Returns tessellator property */ | ||||
| void GLAPIENTRY | ||||
| gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) | ||||
| { | ||||
|    switch (which) { | ||||
|    case GLU_TESS_TOLERANCE: | ||||
|       /* tolerance should be in range [0..1] */ | ||||
|       assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); | ||||
|       *value= tess->relTolerance; | ||||
|       break; | ||||
|    case GLU_TESS_WINDING_RULE: | ||||
|       assert(tess->windingRule == GLU_TESS_WINDING_ODD || | ||||
| 	     tess->windingRule == GLU_TESS_WINDING_NONZERO || | ||||
| 	     tess->windingRule == GLU_TESS_WINDING_POSITIVE || | ||||
| 	     tess->windingRule == GLU_TESS_WINDING_NEGATIVE || | ||||
| 	     tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); | ||||
|       *value= tess->windingRule; | ||||
|       break; | ||||
|    case GLU_TESS_BOUNDARY_ONLY: | ||||
|       assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); | ||||
|       *value= tess->boundaryOnly; | ||||
|       break; | ||||
|    default: | ||||
|       *value= 0.0; | ||||
|       CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); | ||||
|       break; | ||||
|    } | ||||
| } /* gluGetTessProperty() */ | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) | ||||
| { | ||||
|   tess->normal[0] = x; | ||||
|   tess->normal[1] = y; | ||||
|   tess->normal[2] = z; | ||||
| } | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) | ||||
| { | ||||
|   switch( which ) { | ||||
|   case GLU_TESS_BEGIN: | ||||
|     tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_BEGIN_DATA: | ||||
|     tess->callBeginData = (fn == NULL) ? | ||||
| 	&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_EDGE_FLAG: | ||||
|     tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : | ||||
| 					(void (GLAPIENTRY *)(GLboolean)) fn; | ||||
|     /* If the client wants boundary edges to be flagged,
 | ||||
|      * we render everything as separate triangles (no strips or fans). | ||||
|      */ | ||||
|     tess->flagBoundary = (fn != NULL); | ||||
|     return; | ||||
|   case GLU_TESS_EDGE_FLAG_DATA: | ||||
|     tess->callEdgeFlagData= (fn == NULL) ? | ||||
| 	&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; | ||||
|     /* If the client wants boundary edges to be flagged,
 | ||||
|      * we render everything as separate triangles (no strips or fans). | ||||
|      */ | ||||
|     tess->flagBoundary = (fn != NULL); | ||||
|     return; | ||||
|   case GLU_TESS_VERTEX: | ||||
|     tess->callVertex = (fn == NULL) ? &noVertex : | ||||
| 				      (void (GLAPIENTRY *)(void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_VERTEX_DATA: | ||||
|     tess->callVertexData = (fn == NULL) ? | ||||
| 	&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_END: | ||||
|     tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_END_DATA: | ||||
|     tess->callEndData = (fn == NULL) ? &__gl_noEndData : | ||||
| 				       (void (GLAPIENTRY *)(void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_ERROR: | ||||
|     tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_ERROR_DATA: | ||||
|     tess->callErrorData = (fn == NULL) ? | ||||
| 	&__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_COMBINE: | ||||
|     tess->callCombine = (fn == NULL) ? &noCombine : | ||||
| 	(void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; | ||||
|     return; | ||||
|   case GLU_TESS_COMBINE_DATA: | ||||
|     tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : | ||||
| 					   (void (GLAPIENTRY *)(GLdouble [3], | ||||
| 						     void *[4], | ||||
| 						     GLfloat [4], | ||||
| 						     void **, | ||||
| 						     void *)) fn; | ||||
|     return; | ||||
|   case GLU_TESS_MESH: | ||||
|     tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; | ||||
|     return; | ||||
|   default: | ||||
|     CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); | ||||
|     return; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) | ||||
| { | ||||
|   GLUhalfEdge *e; | ||||
| 
 | ||||
|   e = tess->lastEdge; | ||||
|   if( e == NULL ) { | ||||
|     /* Make a self-loop (one vertex, one edge). */ | ||||
| 
 | ||||
|     e = __gl_meshMakeEdge( tess->mesh ); | ||||
|     if (e == NULL) return 0; | ||||
|     if ( !__gl_meshSplice( e, e->Sym ) ) return 0; | ||||
|   } else { | ||||
|     /* Create a new vertex and edge which immediately follow e
 | ||||
|      * in the ordering around the left face. | ||||
|      */ | ||||
|     if (__gl_meshSplitEdge( e ) == NULL) return 0; | ||||
|     e = e->Lnext; | ||||
|   } | ||||
| 
 | ||||
|   /* The new vertex is now e->Org. */ | ||||
|   e->Org->data = data; | ||||
|   e->Org->coords[0] = coords[0]; | ||||
|   e->Org->coords[1] = coords[1]; | ||||
|   e->Org->coords[2] = coords[2]; | ||||
| 
 | ||||
|   /* The winding of an edge says how the winding number changes as we
 | ||||
|    * cross from the edge''s right face to its left face.  We add the | ||||
|    * vertices in such an order that a CCW contour will add +1 to | ||||
|    * the winding number of the region inside the contour. | ||||
|    */ | ||||
|   e->winding = 1; | ||||
|   e->Sym->winding = -1; | ||||
| 
 | ||||
|   tess->lastEdge = e; | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) | ||||
| { | ||||
|   CachedVertex *v = &tess->cache[tess->cacheCount]; | ||||
| 
 | ||||
|   v->data = data; | ||||
|   v->coords[0] = coords[0]; | ||||
|   v->coords[1] = coords[1]; | ||||
|   v->coords[2] = coords[2]; | ||||
|   ++tess->cacheCount; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int EmptyCache( GLUtesselator *tess ) | ||||
| { | ||||
|   CachedVertex *v = tess->cache; | ||||
|   CachedVertex *vLast; | ||||
| 
 | ||||
|   tess->mesh = __gl_meshNewMesh(); | ||||
|   if (tess->mesh == NULL) return 0; | ||||
| 
 | ||||
|   for( vLast = v + tess->cacheCount; v < vLast; ++v ) { | ||||
|     if ( !AddVertex( tess, v->coords, v->data ) ) return 0; | ||||
|   } | ||||
|   tess->cacheCount = 0; | ||||
|   tess->emptyCache = FALSE; | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) | ||||
| { | ||||
|   int i, tooLarge = FALSE; | ||||
|   GLdouble x, clamped[3]; | ||||
| 
 | ||||
|   RequireState( tess, T_IN_CONTOUR ); | ||||
| 
 | ||||
|   if( tess->emptyCache ) { | ||||
|     if ( !EmptyCache( tess ) ) { | ||||
|        CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); | ||||
|        return; | ||||
|     } | ||||
|     tess->lastEdge = NULL; | ||||
|   } | ||||
|   for( i = 0; i < 3; ++i ) { | ||||
|     x = coords[i]; | ||||
|     if( x < - GLU_TESS_MAX_COORD ) { | ||||
|       x = - GLU_TESS_MAX_COORD; | ||||
|       tooLarge = TRUE; | ||||
|     } | ||||
|     if( x > GLU_TESS_MAX_COORD ) { | ||||
|       x = GLU_TESS_MAX_COORD; | ||||
|       tooLarge = TRUE; | ||||
|     } | ||||
|     clamped[i] = x; | ||||
|   } | ||||
|   if( tooLarge ) { | ||||
|     CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); | ||||
|   } | ||||
| 
 | ||||
|   if( tess->mesh == NULL ) { | ||||
|     if( tess->cacheCount < TESS_MAX_CACHE ) { | ||||
|       CacheVertex( tess, clamped, data ); | ||||
|       return; | ||||
|     } | ||||
|     if ( !EmptyCache( tess ) ) { | ||||
|        CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); | ||||
|        return; | ||||
|     } | ||||
|   } | ||||
|   if ( !AddVertex( tess, clamped, data ) ) { | ||||
|        CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessBeginPolygon( GLUtesselator *tess, void *data ) | ||||
| { | ||||
|   RequireState( tess, T_DORMANT ); | ||||
| 
 | ||||
|   tess->state = T_IN_POLYGON; | ||||
|   tess->cacheCount = 0; | ||||
|   tess->emptyCache = FALSE; | ||||
|   tess->mesh = NULL; | ||||
| 
 | ||||
|   tess->polygonData= data; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessBeginContour( GLUtesselator *tess ) | ||||
| { | ||||
|   RequireState( tess, T_IN_POLYGON ); | ||||
| 
 | ||||
|   tess->state = T_IN_CONTOUR; | ||||
|   tess->lastEdge = NULL; | ||||
|   if( tess->cacheCount > 0 ) { | ||||
|     /* Just set a flag so we don't get confused by empty contours
 | ||||
|      * -- these can be generated accidentally with the obsolete | ||||
|      * NextContour() interface. | ||||
|      */ | ||||
|     tess->emptyCache = TRUE; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessEndContour( GLUtesselator *tess ) | ||||
| { | ||||
|   RequireState( tess, T_IN_CONTOUR ); | ||||
|   tess->state = T_IN_POLYGON; | ||||
| } | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluTessEndPolygon( GLUtesselator *tess ) | ||||
| { | ||||
|   GLUmesh *mesh; | ||||
| 
 | ||||
|   if (setjmp(tess->env) != 0) {  | ||||
|      /* come back here if out of memory */ | ||||
|      CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); | ||||
|      return; | ||||
|   } | ||||
| 
 | ||||
|   RequireState( tess, T_IN_POLYGON ); | ||||
|   tess->state = T_DORMANT; | ||||
| 
 | ||||
|   if( tess->mesh == NULL ) { | ||||
|     if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { | ||||
| 
 | ||||
|       /* Try some special code to make the easy cases go quickly
 | ||||
|        * (eg. convex polygons).  This code does NOT handle multiple contours, | ||||
|        * intersections, edge flags, and of course it does not generate | ||||
|        * an explicit mesh either. | ||||
|        */ | ||||
|       if( __gl_renderCache( tess )) { | ||||
| 	tess->polygonData= NULL; | ||||
| 	return; | ||||
|       } | ||||
|     } | ||||
|     if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ | ||||
|   } | ||||
| 
 | ||||
|   /* Determine the polygon normal and project vertices onto the plane
 | ||||
|    * of the polygon. | ||||
|    */ | ||||
|   __gl_projectPolygon( tess ); | ||||
| 
 | ||||
|   /* __gl_computeInterior( tess ) computes the planar arrangement specified
 | ||||
|    * by the given contours, and further subdivides this arrangement | ||||
|    * into regions.  Each region is marked "inside" if it belongs | ||||
|    * to the polygon, according to the rule given by tess->windingRule. | ||||
|    * Each interior region is guaranteed be monotone. | ||||
|    */ | ||||
|   if ( !__gl_computeInterior( tess ) ) { | ||||
|      longjmp(tess->env,1);	/* could've used a label */ | ||||
|   } | ||||
| 
 | ||||
|   mesh = tess->mesh; | ||||
|   if( ! tess->fatalError ) { | ||||
|     int rc = 1; | ||||
| 
 | ||||
|     /* If the user wants only the boundary contours, we throw away all edges
 | ||||
|      * except those which separate the interior from the exterior. | ||||
|      * Otherwise we tessellate all the regions marked "inside". | ||||
|      */ | ||||
|     if( tess->boundaryOnly ) { | ||||
|       rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); | ||||
|     } else { | ||||
|       rc = __gl_meshTessellateInterior( mesh ); | ||||
|     } | ||||
|     if (rc == 0) longjmp(tess->env,1);	/* could've used a label */ | ||||
| 
 | ||||
|     __gl_meshCheckMesh( mesh ); | ||||
| 
 | ||||
|     if( tess->callBegin != &noBegin || tess->callEnd != &noEnd | ||||
|        || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag | ||||
|        || tess->callBeginData != &__gl_noBeginData | ||||
|        || tess->callEndData != &__gl_noEndData | ||||
|        || tess->callVertexData != &__gl_noVertexData | ||||
|        || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) | ||||
|     { | ||||
|       if( tess->boundaryOnly ) { | ||||
| 	__gl_renderBoundary( tess, mesh );  /* output boundary contours */ | ||||
|       } else { | ||||
| 	__gl_renderMesh( tess, mesh );	   /* output strips and fans */ | ||||
|       } | ||||
|     } | ||||
|     if( tess->callMesh != &noMesh ) { | ||||
| 
 | ||||
|       /* Throw away the exterior faces, so that all faces are interior.
 | ||||
|        * This way the user doesn't have to check the "inside" flag, | ||||
|        * and we don't need to even reveal its existence.  It also leaves | ||||
|        * the freedom for an implementation to not generate the exterior | ||||
|        * faces in the first place. | ||||
|        */ | ||||
|       __gl_meshDiscardExterior( mesh ); | ||||
|       (*tess->callMesh)( mesh );		/* user wants the mesh itself */ | ||||
|       tess->mesh = NULL; | ||||
|       tess->polygonData= NULL; | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   __gl_meshDeleteMesh( mesh ); | ||||
|   tess->polygonData= NULL; | ||||
|   tess->mesh = NULL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*XXXblythe unused function*/ | ||||
| #if 0 | ||||
| void GLAPIENTRY | ||||
| gluDeleteMesh( GLUmesh *mesh ) | ||||
| { | ||||
|   __gl_meshDeleteMesh( mesh ); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*******************************************************/ | ||||
| 
 | ||||
| /* Obsolete calls -- for backward compatibility */ | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluBeginPolygon( GLUtesselator *tess ) | ||||
| { | ||||
|   gluTessBeginPolygon( tess, NULL ); | ||||
|   gluTessBeginContour( tess ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*ARGSUSED*/ | ||||
| void GLAPIENTRY | ||||
| gluNextContour( GLUtesselator *tess, GLenum type ) | ||||
| { | ||||
|   gluTessEndContour( tess ); | ||||
|   gluTessBeginContour( tess ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLAPIENTRY | ||||
| gluEndPolygon( GLUtesselator *tess ) | ||||
| { | ||||
|   gluTessEndContour( tess ); | ||||
|   gluTessEndPolygon( tess ); | ||||
| } | ||||
							
								
								
									
										165
									
								
								src/glu-libtess/src/tess.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/glu-libtess/src/tess.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,165 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __tess_h_ | ||||
| #define __tess_h_ | ||||
| 
 | ||||
| #include "glu-libtess.h" | ||||
| #include <setjmp.h> | ||||
| #include "mesh.h" | ||||
| #include "dict.h" | ||||
| #include "priorityq.h" | ||||
| 
 | ||||
| /* The begin/end calls must be properly nested.  We keep track of
 | ||||
|  * the current state to enforce the ordering. | ||||
|  */ | ||||
| enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR }; | ||||
| 
 | ||||
| /* We cache vertex data for single-contour polygons so that we can
 | ||||
|  * try a quick-and-dirty decomposition first. | ||||
|  */ | ||||
| #define TESS_MAX_CACHE	100 | ||||
| 
 | ||||
| typedef struct CachedVertex { | ||||
|   GLdouble	coords[3]; | ||||
|   void		*data; | ||||
| } CachedVertex; | ||||
| 
 | ||||
| struct GLUtesselator { | ||||
| 
 | ||||
|   /*** state needed for collecting the input data ***/ | ||||
| 
 | ||||
|   enum TessState state;		/* what begin/end calls have we seen? */ | ||||
| 
 | ||||
|   GLUhalfEdge	*lastEdge;	/* lastEdge->Org is the most recent vertex */ | ||||
|   GLUmesh	*mesh;		/* stores the input contours, and eventually
 | ||||
|                                    the tessellation itself */ | ||||
| 
 | ||||
|   void		(GLAPIENTRY *callError)( GLenum errnum ); | ||||
| 
 | ||||
|   /*** state needed for projecting onto the sweep plane ***/ | ||||
| 
 | ||||
|   GLdouble	normal[3];	/* user-specified normal (if provided) */ | ||||
|   GLdouble	sUnit[3];	/* unit vector in s-direction (debugging) */ | ||||
|   GLdouble	tUnit[3];	/* unit vector in t-direction (debugging) */ | ||||
| 
 | ||||
|   /*** state needed for the line sweep ***/ | ||||
| 
 | ||||
|   GLdouble	relTolerance;	/* tolerance for merging features */ | ||||
|   GLenum	windingRule;	/* rule for determining polygon interior */ | ||||
|   GLboolean	fatalError;	/* fatal error: needed combine callback */ | ||||
| 
 | ||||
|   Dict		*dict;		/* edge dictionary for sweep line */ | ||||
|   PriorityQ	*pq;		/* priority queue of vertex events */ | ||||
|   GLUvertex	*event;		/* current sweep event being processed */ | ||||
| 
 | ||||
|   void		(GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4], | ||||
| 			        GLfloat weight[4], void **outData ); | ||||
| 
 | ||||
|   /*** state needed for rendering callbacks (see render.c) ***/ | ||||
| 
 | ||||
|   GLboolean	flagBoundary;	/* mark boundary edges (use EdgeFlag) */ | ||||
|   GLboolean	boundaryOnly;	/* Extract contours, not triangles */ | ||||
|   GLUface	*lonelyTriList; | ||||
|     /* list of triangles which could not be rendered as strips or fans */ | ||||
| 
 | ||||
|   void		(GLAPIENTRY *callBegin)( GLenum type ); | ||||
|   void		(GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge ); | ||||
|   void		(GLAPIENTRY *callVertex)( void *data ); | ||||
|   void		(GLAPIENTRY *callEnd)( void ); | ||||
|   void		(GLAPIENTRY *callMesh)( GLUmesh *mesh ); | ||||
| 
 | ||||
| 
 | ||||
|   /*** state needed to cache single-contour polygons for renderCache() */ | ||||
| 
 | ||||
|   GLboolean	emptyCache;		/* empty cache on next vertex() call */ | ||||
|   int		cacheCount;		/* number of cached vertices */ | ||||
|   CachedVertex	cache[TESS_MAX_CACHE];	/* the vertex data */ | ||||
| 
 | ||||
|   /*** rendering callbacks that also pass polygon data  ***/  | ||||
|   void		(GLAPIENTRY *callBeginData)( GLenum type, void *polygonData ); | ||||
|   void		(GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,  | ||||
| 				     void *polygonData ); | ||||
|   void		(GLAPIENTRY *callVertexData)( void *data, void *polygonData ); | ||||
|   void		(GLAPIENTRY *callEndData)( void *polygonData ); | ||||
|   void		(GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData ); | ||||
|   void		(GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4], | ||||
| 				    GLfloat weight[4], void **outData, | ||||
| 				    void *polygonData ); | ||||
| 
 | ||||
|   jmp_buf env;			/* place to jump to when memAllocs fail */ | ||||
| 
 | ||||
|   void *polygonData;		/* client data for current polygon */ | ||||
| }; | ||||
| 
 | ||||
| void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ); | ||||
| void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ); | ||||
| void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ); | ||||
| void GLAPIENTRY __gl_noEndData( void *polygonData ); | ||||
| void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ); | ||||
| void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], | ||||
| 			 GLfloat weight[4], void **outData, | ||||
| 			 void *polygonData ); | ||||
| 
 | ||||
| #define CALL_BEGIN_OR_BEGIN_DATA(a) \ | ||||
|    if (tess->callBeginData != &__gl_noBeginData) \ | ||||
|       (*tess->callBeginData)((a),tess->polygonData); \ | ||||
|    else (*tess->callBegin)((a)); | ||||
| 
 | ||||
| #define CALL_VERTEX_OR_VERTEX_DATA(a) \ | ||||
|    if (tess->callVertexData != &__gl_noVertexData) \ | ||||
|       (*tess->callVertexData)((a),tess->polygonData); \ | ||||
|    else (*tess->callVertex)((a)); | ||||
| 
 | ||||
| #define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \ | ||||
|    if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \ | ||||
|       (*tess->callEdgeFlagData)((a),tess->polygonData); \ | ||||
|    else (*tess->callEdgeFlag)((a)); | ||||
| 
 | ||||
| #define CALL_END_OR_END_DATA() \ | ||||
|    if (tess->callEndData != &__gl_noEndData) \ | ||||
|       (*tess->callEndData)(tess->polygonData); \ | ||||
|    else (*tess->callEnd)(); | ||||
| 
 | ||||
| #define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \ | ||||
|    if (tess->callCombineData != &__gl_noCombineData) \ | ||||
|       (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \ | ||||
|    else (*tess->callCombine)((a),(b),(c),(d)); | ||||
| 
 | ||||
| #define CALL_ERROR_OR_ERROR_DATA(a) \ | ||||
|    if (tess->callErrorData != &__gl_noErrorData) \ | ||||
|       (*tess->callErrorData)((a),tess->polygonData); \ | ||||
|    else (*tess->callError)((a)); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										201
									
								
								src/glu-libtess/src/tessmono.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								src/glu-libtess/src/tessmono.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,201 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #include "gluos.h" | ||||
| #include <stdlib.h> | ||||
| #include "geom.h" | ||||
| #include "mesh.h" | ||||
| #include "tessmono.h" | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #define AddWinding(eDst,eSrc)	(eDst->winding += eSrc->winding, \ | ||||
| 				 eDst->Sym->winding += eSrc->Sym->winding) | ||||
| 
 | ||||
| /* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
 | ||||
|  * (what else would it do??)  The region must consist of a single | ||||
|  * loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this | ||||
|  * case means that any vertical line intersects the interior of the | ||||
|  * region in a single interval.   | ||||
|  * | ||||
|  * Tessellation consists of adding interior edges (actually pairs of | ||||
|  * half-edges), to split the region into non-overlapping triangles. | ||||
|  * | ||||
|  * The basic idea is explained in Preparata and Shamos (which I don''t | ||||
|  * have handy right now), although their implementation is more | ||||
|  * complicated than this one.  The are two edge chains, an upper chain | ||||
|  * and a lower chain.  We process all vertices from both chains in order, | ||||
|  * from right to left. | ||||
|  * | ||||
|  * The algorithm ensures that the following invariant holds after each | ||||
|  * vertex is processed: the untessellated region consists of two | ||||
|  * chains, where one chain (say the upper) is a single edge, and | ||||
|  * the other chain is concave.  The left vertex of the single edge | ||||
|  * is always to the left of all vertices in the concave chain. | ||||
|  * | ||||
|  * Each step consists of adding the rightmost unprocessed vertex to one | ||||
|  * of the two chains, and forming a fan of triangles from the rightmost | ||||
|  * of two chain endpoints.  Determining whether we can add each triangle | ||||
|  * to the fan is a simple orientation test.  By making the fan as large | ||||
|  * as possible, we restore the invariant (check it yourself). | ||||
|  */ | ||||
| int __gl_meshTessellateMonoRegion( GLUface *face ) | ||||
| { | ||||
|   GLUhalfEdge *up, *lo; | ||||
| 
 | ||||
|   /* All edges are oriented CCW around the boundary of the region.
 | ||||
|    * First, find the half-edge whose origin vertex is rightmost. | ||||
|    * Since the sweep goes from left to right, face->anEdge should | ||||
|    * be close to the edge we want. | ||||
|    */ | ||||
|   up = face->anEdge; | ||||
|   assert( up->Lnext != up && up->Lnext->Lnext != up ); | ||||
| 
 | ||||
|   for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) | ||||
|     ; | ||||
|   for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) | ||||
|     ; | ||||
|   lo = up->Lprev; | ||||
| 
 | ||||
|   while( up->Lnext != lo ) { | ||||
|     if( VertLeq( up->Dst, lo->Org )) { | ||||
|       /* up->Dst is on the left.  It is safe to form triangles from lo->Org.
 | ||||
|        * The EdgeGoesLeft test guarantees progress even when some triangles | ||||
|        * are CW, given that the upper and lower chains are truly monotone. | ||||
|        */ | ||||
|       while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) | ||||
| 	     || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { | ||||
| 	GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); | ||||
| 	if (tempHalfEdge == NULL) return 0; | ||||
| 	lo = tempHalfEdge->Sym; | ||||
|       } | ||||
|       lo = lo->Lprev; | ||||
|     } else { | ||||
|       /* lo->Org is on the left.  We can make CCW triangles from up->Dst. */ | ||||
|       while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) | ||||
| 	     || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { | ||||
| 	GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev ); | ||||
| 	if (tempHalfEdge == NULL) return 0; | ||||
| 	up = tempHalfEdge->Sym; | ||||
|       } | ||||
|       up = up->Lnext; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* Now lo->Org == up->Dst == the leftmost vertex.  The remaining region
 | ||||
|    * can be tessellated in a fan from this leftmost vertex. | ||||
|    */ | ||||
|   assert( lo->Lnext != up ); | ||||
|   while( lo->Lnext->Lnext != up ) { | ||||
|     GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); | ||||
|     if (tempHalfEdge == NULL) return 0; | ||||
|     lo = tempHalfEdge->Sym; | ||||
|   } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshTessellateInterior( mesh ) tessellates each region of
 | ||||
|  * the mesh which is marked "inside" the polygon.  Each such region | ||||
|  * must be monotone. | ||||
|  */ | ||||
| int __gl_meshTessellateInterior( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *f, *next; | ||||
| 
 | ||||
|   /*LINTED*/ | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { | ||||
|     /* Make sure we don''t try to tessellate the new triangles. */ | ||||
|     next = f->next; | ||||
|     if( f->inside ) { | ||||
|       if ( !__gl_meshTessellateMonoRegion( f ) ) return 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
 | ||||
|  * which are not marked "inside" the polygon.  Since further mesh operations | ||||
|  * on NULL faces are not allowed, the main purpose is to clean up the | ||||
|  * mesh so that exterior loops are not represented in the data structure. | ||||
|  */ | ||||
| void __gl_meshDiscardExterior( GLUmesh *mesh ) | ||||
| { | ||||
|   GLUface *f, *next; | ||||
| 
 | ||||
|   /*LINTED*/ | ||||
|   for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { | ||||
|     /* Since f will be destroyed, save its next pointer. */ | ||||
|     next = f->next; | ||||
|     if( ! f->inside ) { | ||||
|       __gl_meshZapFace( f ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #define MARKED_FOR_DELETION	0x7fffffff | ||||
| 
 | ||||
| /* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
 | ||||
|  * winding numbers on all edges so that regions marked "inside" the | ||||
|  * polygon have a winding number of "value", and regions outside | ||||
|  * have a winding number of 0. | ||||
|  * | ||||
|  * If keepOnlyBoundary is TRUE, it also deletes all edges which do not | ||||
|  * separate an interior region from an exterior one. | ||||
|  */ | ||||
| int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, | ||||
| 			        GLboolean keepOnlyBoundary ) | ||||
| { | ||||
|   GLUhalfEdge *e, *eNext; | ||||
| 
 | ||||
|   for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { | ||||
|     eNext = e->next; | ||||
|     if( e->Rface->inside != e->Lface->inside ) { | ||||
| 
 | ||||
|       /* This is a boundary edge (one side is interior, one is exterior). */ | ||||
|       e->winding = (e->Lface->inside) ? value : -value; | ||||
|     } else { | ||||
| 
 | ||||
|       /* Both regions are interior, or both are exterior. */ | ||||
|       if( ! keepOnlyBoundary ) { | ||||
| 	e->winding = 0; | ||||
|       } else { | ||||
| 	if ( !__gl_meshDelete( e ) ) return 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
							
								
								
									
										71
									
								
								src/glu-libtess/src/tessmono.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/glu-libtess/src/tessmono.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| /*
 | ||||
|  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) | ||||
|  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice including the dates of first publication and | ||||
|  * either this permission notice or a reference to | ||||
|  * http://oss.sgi.com/projects/FreeB/
 | ||||
|  * shall be included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | ||||
|  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  * | ||||
|  * Except as contained in this notice, the name of Silicon Graphics, Inc. | ||||
|  * shall not be used in advertising or otherwise to promote the sale, use or | ||||
|  * other dealings in this Software without prior written authorization from | ||||
|  * Silicon Graphics, Inc. | ||||
|  */ | ||||
| /*
 | ||||
| ** Author: Eric Veach, July 1994. | ||||
| ** | ||||
| */ | ||||
| 
 | ||||
| #ifndef __tessmono_h_ | ||||
| #define __tessmono_h_ | ||||
| 
 | ||||
| /* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
 | ||||
|  * (what else would it do??)  The region must consist of a single | ||||
|  * loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this | ||||
|  * case means that any vertical line intersects the interior of the | ||||
|  * region in a single interval.   | ||||
|  * | ||||
|  * Tessellation consists of adding interior edges (actually pairs of | ||||
|  * half-edges), to split the region into non-overlapping triangles. | ||||
|  * | ||||
|  * __gl_meshTessellateInterior( mesh ) tessellates each region of | ||||
|  * the mesh which is marked "inside" the polygon.  Each such region | ||||
|  * must be monotone. | ||||
|  * | ||||
|  * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces | ||||
|  * which are not marked "inside" the polygon.  Since further mesh operations | ||||
|  * on NULL faces are not allowed, the main purpose is to clean up the | ||||
|  * mesh so that exterior loops are not represented in the data structure. | ||||
|  * | ||||
|  * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the | ||||
|  * winding numbers on all edges so that regions marked "inside" the | ||||
|  * polygon have a winding number of "value", and regions outside | ||||
|  * have a winding number of 0. | ||||
|  * | ||||
|  * If keepOnlyBoundary is TRUE, it also deletes all edges which do not | ||||
|  * separate an interior region from an exterior one. | ||||
|  */ | ||||
| 
 | ||||
| int __gl_meshTessellateMonoRegion( GLUface *face ); | ||||
| int __gl_meshTessellateInterior( GLUmesh *mesh ); | ||||
| void __gl_meshDiscardExterior( GLUmesh *mesh ); | ||||
| int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, | ||||
| 			        GLboolean keepOnlyBoundary ); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -187,6 +187,7 @@ target_link_libraries(libslic3r | |||
|     ${EXPAT_LIBRARIES} | ||||
|     ${GLEW_LIBRARIES} | ||||
|     ${PNG_LIBRARIES} | ||||
|     glu-libtess | ||||
|     polypartition | ||||
|     poly2tri | ||||
|     qhull | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv