mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-07-04 04:50:22 +00:00
Remove dead glues directory
This commit is contained in:
parent
0122c6c11e
commit
3983879a44
|
@ -1 +0,0 @@
|
|||
glues.h
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES 1.0 CM port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __glues_h__
|
||||
#define __glues_h__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif /* APIENTRYP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
/* Boolean */
|
||||
#define GLU_FALSE 0
|
||||
#define GLU_TRUE 1
|
||||
|
||||
/* Version */
|
||||
#define GLU_VERSION_1_1 1
|
||||
#define GLU_VERSION_1_2 1
|
||||
#define GLU_VERSION_1_3 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* QuadricDrawStyle */
|
||||
#define GLU_POINT 100010
|
||||
#define GLU_LINE 100011
|
||||
#define GLU_FILL 100012
|
||||
#define GLU_SILHOUETTE 100013
|
||||
|
||||
/* QuadricCallback */
|
||||
#define GLU_ERROR 100103
|
||||
|
||||
/* QuadricNormal */
|
||||
#define GLU_SMOOTH 100000
|
||||
#define GLU_FLAT 100001
|
||||
#define GLU_NONE 100002
|
||||
|
||||
/* QuadricOrientation */
|
||||
#define GLU_OUTSIDE 100020
|
||||
#define GLU_INSIDE 100021
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class GLUquadric;
|
||||
class GLUtesselator;
|
||||
#else
|
||||
typedef struct GLUquadric GLUquadric;
|
||||
typedef struct GLUtesselator GLUtesselator;
|
||||
#endif
|
||||
|
||||
typedef GLUquadric GLUquadricObj;
|
||||
typedef GLUtesselator GLUtesselatorObj;
|
||||
typedef GLUtesselator GLUtriangulatorObj;
|
||||
|
||||
/* Internal convenience typedefs */
|
||||
typedef void (APIENTRYP _GLUfuncptr)();
|
||||
|
||||
GLAPI GLboolean APIENTRY gluCheckExtension(const GLubyte* extName, const GLubyte* extString);
|
||||
GLAPI void APIENTRY gluCylinder(GLUquadric* quad, GLfloat base, GLfloat top, GLfloat height, GLint slices, GLint stacks);
|
||||
GLAPI void APIENTRY gluDeleteQuadric(GLUquadric* quad);
|
||||
GLAPI void APIENTRY gluDisk(GLUquadric* quad, GLfloat inner, GLfloat outer, GLint slices, GLint loops);
|
||||
GLAPI const GLubyte* APIENTRY gluErrorString(GLenum error);
|
||||
GLAPI const GLubyte * APIENTRY gluGetString(GLenum name);
|
||||
GLAPI void APIENTRY gluLookAt(GLfloat eyeX, GLfloat eyeY, GLfloat eyeZ, GLfloat centerX, GLfloat centerY, GLfloat centerZ, GLfloat upX, GLfloat upY, GLfloat upZ);
|
||||
GLAPI GLUquadric* APIENTRY gluNewQuadric(void);
|
||||
GLAPI void APIENTRY gluOrtho2D(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top);
|
||||
GLAPI void APIENTRY gluPartialDisk(GLUquadric* quad, GLfloat inner, GLfloat outer, GLint slices, GLint loops, GLfloat start, GLfloat sweep);
|
||||
GLAPI void APIENTRY gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
|
||||
GLAPI void APIENTRY gluPickMatrix(GLfloat x, GLfloat y, GLfloat delX, GLfloat delY, GLint *viewport);
|
||||
GLAPI GLint APIENTRY gluProject(GLfloat objX, GLfloat objY, GLfloat objZ, const GLfloat *model, const GLfloat *proj, const GLint *view, GLfloat* winX, GLfloat* winY, GLfloat* winZ);
|
||||
GLAPI void APIENTRY gluQuadricCallback(GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
GLAPI void APIENTRY gluQuadricDrawStyle(GLUquadric* quad, GLenum draw);
|
||||
GLAPI void APIENTRY gluQuadricNormals(GLUquadric* quad, GLenum normal);
|
||||
GLAPI void APIENTRY gluQuadricOrientation(GLUquadric* quad, GLenum orientation);
|
||||
GLAPI void APIENTRY gluQuadricTexture(GLUquadric* quad, GLboolean texture);
|
||||
GLAPI void APIENTRY gluSphere(GLUquadric* quad, GLfloat radius, GLint slices, GLint stacks);
|
||||
GLAPI GLint APIENTRY gluUnProject(GLfloat winX, GLfloat winY, GLfloat winZ, const GLfloat *model, const GLfloat *proj, const GLint *view, GLfloat* objX, GLfloat* objY, GLfloat* objZ);
|
||||
GLAPI GLint APIENTRY gluUnProject4(GLfloat winX, GLfloat winY, GLfloat winZ, GLfloat clipW, const GLfloat *model, const GLfloat *proj, const GLint *view, GLfloat nearVal, GLfloat farVal, GLfloat* objX, GLfloat* objY, GLfloat* objZ, GLfloat* objW);
|
||||
GLAPI GLint APIENTRY gluScaleImage(GLenum format, GLsizei widthin,
|
||||
GLsizei heightin, GLenum typein,
|
||||
const void* datain, GLsizei widthout,
|
||||
GLsizei heightout, GLenum typeout, void* dataout);
|
||||
GLAPI GLint APIENTRY gluBuild2DMipmapLevels(GLenum target, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, GLint userLevel, GLint baseLevel,
|
||||
GLint maxLevel, const void *data);
|
||||
GLAPI GLint APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
|
||||
#define GLU_TESS_MAX_COORD 1.0e37f
|
||||
|
||||
/* 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
|
||||
|
||||
GLAPI void APIENTRY gluBeginPolygon(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluDeleteTess(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluEndPolygon(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluGetTessProperty(GLUtesselator* tess, GLenum which, GLfloat* data);
|
||||
GLAPI GLUtesselator* APIENTRY gluNewTess(void);
|
||||
GLAPI void APIENTRY gluNextContour(GLUtesselator* tess, GLenum type);
|
||||
GLAPI void APIENTRY gluTessBeginContour(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluTessBeginPolygon(GLUtesselator* tess, GLvoid* data);
|
||||
GLAPI void APIENTRY gluTessCallback(GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
GLAPI void APIENTRY gluTessEndContour(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluTessEndPolygon(GLUtesselator* tess);
|
||||
GLAPI void APIENTRY gluTessNormal(GLUtesselator* tess, GLfloat valueX, GLfloat valueY, GLfloat valueZ);
|
||||
GLAPI void APIENTRY gluTessProperty(GLUtesselator* tess, GLenum which, GLfloat data);
|
||||
GLAPI void APIENTRY gluTessVertex(GLUtesselator* tess, GLfloat* location, GLvoid* data);
|
||||
|
||||
/* NurbsError */
|
||||
#define GLU_NURBS_ERROR1 100251
|
||||
#define GLU_NURBS_ERROR2 100252
|
||||
#define GLU_NURBS_ERROR3 100253
|
||||
#define GLU_NURBS_ERROR4 100254
|
||||
#define GLU_NURBS_ERROR5 100255
|
||||
#define GLU_NURBS_ERROR6 100256
|
||||
#define GLU_NURBS_ERROR7 100257
|
||||
#define GLU_NURBS_ERROR8 100258
|
||||
#define GLU_NURBS_ERROR9 100259
|
||||
#define GLU_NURBS_ERROR10 100260
|
||||
#define GLU_NURBS_ERROR11 100261
|
||||
#define GLU_NURBS_ERROR12 100262
|
||||
#define GLU_NURBS_ERROR13 100263
|
||||
#define GLU_NURBS_ERROR14 100264
|
||||
#define GLU_NURBS_ERROR15 100265
|
||||
#define GLU_NURBS_ERROR16 100266
|
||||
#define GLU_NURBS_ERROR17 100267
|
||||
#define GLU_NURBS_ERROR18 100268
|
||||
#define GLU_NURBS_ERROR19 100269
|
||||
#define GLU_NURBS_ERROR20 100270
|
||||
#define GLU_NURBS_ERROR21 100271
|
||||
#define GLU_NURBS_ERROR22 100272
|
||||
#define GLU_NURBS_ERROR23 100273
|
||||
#define GLU_NURBS_ERROR24 100274
|
||||
#define GLU_NURBS_ERROR25 100275
|
||||
#define GLU_NURBS_ERROR26 100276
|
||||
#define GLU_NURBS_ERROR27 100277
|
||||
#define GLU_NURBS_ERROR28 100278
|
||||
#define GLU_NURBS_ERROR29 100279
|
||||
#define GLU_NURBS_ERROR30 100280
|
||||
#define GLU_NURBS_ERROR31 100281
|
||||
#define GLU_NURBS_ERROR32 100282
|
||||
#define GLU_NURBS_ERROR33 100283
|
||||
#define GLU_NURBS_ERROR34 100284
|
||||
#define GLU_NURBS_ERROR35 100285
|
||||
#define GLU_NURBS_ERROR36 100286
|
||||
#define GLU_NURBS_ERROR37 100287
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __glues_h__ */
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES 1.0 CM port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "glues_error.h"
|
||||
|
||||
static unsigned char* __gluNurbsErrors[]=
|
||||
{
|
||||
(unsigned char*) " ",
|
||||
(unsigned char*) "spline order un-supported",
|
||||
(unsigned char*) "too few knots",
|
||||
(unsigned char*) "valid knot range is empty",
|
||||
(unsigned char*) "decreasing knot sequence knot",
|
||||
(unsigned char*) "knot multiplicity greater than order of spline",
|
||||
(unsigned char*) "gluEndCurve() must follow gluBeginCurve()",
|
||||
(unsigned char*) "gluBeginCurve() must precede gluEndCurve()",
|
||||
(unsigned char*) "missing or extra geometric data",
|
||||
(unsigned char*) "can't draw piecewise linear trimming curves",
|
||||
(unsigned char*) "missing or extra domain data",
|
||||
(unsigned char*) "missing or extra domain data",
|
||||
(unsigned char*) "gluEndTrim() must precede gluEndSurface()",
|
||||
(unsigned char*) "gluBeginSurface() must precede gluEndSurface()",
|
||||
(unsigned char*) "curve of improper type passed as trim curve",
|
||||
(unsigned char*) "gluBeginSurface() must precede gluBeginTrim()",
|
||||
(unsigned char*) "gluEndTrim() must follow gluBeginTrim()",
|
||||
(unsigned char*) "gluBeginTrim() must precede gluEndTrim()",
|
||||
(unsigned char*) "invalid or missing trim curve",
|
||||
(unsigned char*) "gluBeginTrim() must precede gluPwlCurve()",
|
||||
(unsigned char*) "piecewise linear trimming curve referenced twice",
|
||||
(unsigned char*) "piecewise linear trimming curve and nurbs curve mixed",
|
||||
(unsigned char*) "improper usage of trim data type",
|
||||
(unsigned char*) "nurbs curve referenced twice",
|
||||
(unsigned char*) "nurbs curve and piecewise linear trimming curve mixed",
|
||||
(unsigned char*) "nurbs surface referenced twice",
|
||||
(unsigned char*) "invalid property",
|
||||
(unsigned char*) "gluEndSurface() must follow gluBeginSurface()",
|
||||
(unsigned char*) "intersecting or misoriented trim curves",
|
||||
(unsigned char*) "intersecting trim curves",
|
||||
(unsigned char*) "UNUSED",
|
||||
(unsigned char*) "unconnected trim curves",
|
||||
(unsigned char*) "unknown knot error",
|
||||
(unsigned char*) "negative vertex count encountered",
|
||||
(unsigned char*) "negative byte-stride encounteed",
|
||||
(unsigned char*) "unknown type descriptor",
|
||||
(unsigned char*) "null control point reference",
|
||||
(unsigned char*) "duplicate point on piecewise linear trimming curve",
|
||||
};
|
||||
|
||||
const unsigned char* __gluNURBSErrorString(int errnum)
|
||||
{
|
||||
return __gluNurbsErrors[errnum];
|
||||
}
|
||||
|
||||
static unsigned char* __gluTessErrors[]=
|
||||
{
|
||||
(unsigned char*) " ",
|
||||
(unsigned char*) "gluTessBeginPolygon() must precede a gluTessEndPolygon()",
|
||||
(unsigned char*) "gluTessBeginContour() must precede a gluTessEndContour()",
|
||||
(unsigned char*) "gluTessEndPolygon() must follow a gluTessBeginPolygon()",
|
||||
(unsigned char*) "gluTessEndContour() must follow a gluTessBeginContour()",
|
||||
(unsigned char*) "a coordinate is too large",
|
||||
(unsigned char*) "need combine callback",
|
||||
};
|
||||
|
||||
const unsigned char* __gluTessErrorString(int errnum)
|
||||
{
|
||||
return __gluTessErrors[errnum];
|
||||
}
|
||||
|
||||
struct token_string
|
||||
{
|
||||
GLuint Token;
|
||||
const char* String;
|
||||
};
|
||||
|
||||
static const struct token_string Errors[]=
|
||||
{
|
||||
/* GL */
|
||||
{GL_NO_ERROR, "no error"},
|
||||
{GL_INVALID_ENUM, "invalid enumerant"},
|
||||
{GL_INVALID_VALUE, "invalid value"},
|
||||
{GL_INVALID_OPERATION, "invalid operation"},
|
||||
{GL_STACK_OVERFLOW, "stack overflow"},
|
||||
{GL_STACK_UNDERFLOW, "stack underflow"},
|
||||
{GL_OUT_OF_MEMORY, "out of memory"},
|
||||
|
||||
/* GLU */
|
||||
{ GLU_INVALID_ENUM, "invalid enumerant"},
|
||||
{ GLU_INVALID_VALUE, "invalid value"},
|
||||
{ GLU_OUT_OF_MEMORY, "out of memory"},
|
||||
{ GLU_INCOMPATIBLE_GL_VERSION, "incompatible gl version"},
|
||||
{ GLU_INVALID_OPERATION, "invalid operation"},
|
||||
{ ~0, NULL } /* end of list indicator */
|
||||
};
|
||||
|
||||
GLAPI const GLubyte* APIENTRY gluErrorString(GLenum errorCode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; Errors[i].String; i++)
|
||||
{
|
||||
if (Errors[i].Token==errorCode)
|
||||
{
|
||||
return (const GLubyte*) Errors[i].String;
|
||||
}
|
||||
}
|
||||
|
||||
if ((errorCode>=GLU_NURBS_ERROR1) && (errorCode<=GLU_NURBS_ERROR37))
|
||||
{
|
||||
return (const GLubyte*)__gluNURBSErrorString(errorCode-(GLU_NURBS_ERROR1-1));
|
||||
}
|
||||
if ((errorCode>=GLU_TESS_ERROR1) && (errorCode<=GLU_TESS_ERROR6))
|
||||
{
|
||||
return (const GLubyte*) __gluTessErrorString(errorCode-(GLU_TESS_ERROR1-1));
|
||||
}
|
||||
|
||||
return (const GLubyte*)0;
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __GLUES_REGISTRY_H__
|
||||
#define __GLUES_REGISTRY_H__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
/* NurbsError */
|
||||
#define GLU_NURBS_ERROR1 100251
|
||||
#define GLU_NURBS_ERROR2 100252
|
||||
#define GLU_NURBS_ERROR3 100253
|
||||
#define GLU_NURBS_ERROR4 100254
|
||||
#define GLU_NURBS_ERROR5 100255
|
||||
#define GLU_NURBS_ERROR6 100256
|
||||
#define GLU_NURBS_ERROR7 100257
|
||||
#define GLU_NURBS_ERROR8 100258
|
||||
#define GLU_NURBS_ERROR9 100259
|
||||
#define GLU_NURBS_ERROR10 100260
|
||||
#define GLU_NURBS_ERROR11 100261
|
||||
#define GLU_NURBS_ERROR12 100262
|
||||
#define GLU_NURBS_ERROR13 100263
|
||||
#define GLU_NURBS_ERROR14 100264
|
||||
#define GLU_NURBS_ERROR15 100265
|
||||
#define GLU_NURBS_ERROR16 100266
|
||||
#define GLU_NURBS_ERROR17 100267
|
||||
#define GLU_NURBS_ERROR18 100268
|
||||
#define GLU_NURBS_ERROR19 100269
|
||||
#define GLU_NURBS_ERROR20 100270
|
||||
#define GLU_NURBS_ERROR21 100271
|
||||
#define GLU_NURBS_ERROR22 100272
|
||||
#define GLU_NURBS_ERROR23 100273
|
||||
#define GLU_NURBS_ERROR24 100274
|
||||
#define GLU_NURBS_ERROR25 100275
|
||||
#define GLU_NURBS_ERROR26 100276
|
||||
#define GLU_NURBS_ERROR27 100277
|
||||
#define GLU_NURBS_ERROR28 100278
|
||||
#define GLU_NURBS_ERROR29 100279
|
||||
#define GLU_NURBS_ERROR30 100280
|
||||
#define GLU_NURBS_ERROR31 100281
|
||||
#define GLU_NURBS_ERROR32 100282
|
||||
#define GLU_NURBS_ERROR33 100283
|
||||
#define GLU_NURBS_ERROR34 100284
|
||||
#define GLU_NURBS_ERROR35 100285
|
||||
#define GLU_NURBS_ERROR36 100286
|
||||
#define GLU_NURBS_ERROR37 100287
|
||||
|
||||
GLAPI const GLubyte* APIENTRY gluErrorString(GLenum errorCode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GLUES_REGISTRY_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __GLUES_MIPMAP_H__
|
||||
#define __GLUES_MIPMAP_H__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
GLAPI GLint APIENTRY gluScaleImage(GLenum format, GLsizei widthin,
|
||||
GLsizei heightin, GLenum typein,
|
||||
const void* datain, GLsizei widthout,
|
||||
GLsizei heightout, GLenum typeout, void* dataout);
|
||||
GLAPI GLint APIENTRY gluBuild2DMipmapLevels(GLenum target, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, GLint userLevel, GLint baseLevel,
|
||||
GLint maxLevel, const void *data);
|
||||
GLAPI GLint APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GLUES_REGISTRY_H__ */
|
|
@ -1,378 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES 1.0 CM port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "glues_project.h"
|
||||
|
||||
/*
|
||||
** Make m an identity matrix
|
||||
*/
|
||||
|
||||
static void __gluMakeIdentityf(GLfloat m[16])
|
||||
{
|
||||
m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
|
||||
m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
|
||||
m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
|
||||
m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY
|
||||
gluOrtho2D(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top)
|
||||
{
|
||||
glOrthof(left, right, bottom, top, -1, 1);
|
||||
}
|
||||
|
||||
#define __glPi 3.14159265358979323846
|
||||
|
||||
GLAPI void APIENTRY
|
||||
gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
|
||||
{
|
||||
GLfloat m[4][4];
|
||||
GLfloat sine, cotangent, deltaZ;
|
||||
GLfloat radians=(GLfloat)(fovy/2.0f*__glPi/180.0f);
|
||||
|
||||
deltaZ=zFar-zNear;
|
||||
sine=(GLfloat)sin(radians);
|
||||
if ((deltaZ==0.0f) || (sine==0.0f) || (aspect==0.0f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
cotangent=(GLfloat)(cos(radians)/sine);
|
||||
|
||||
__gluMakeIdentityf(&m[0][0]);
|
||||
m[0][0] = cotangent / aspect;
|
||||
m[1][1] = cotangent;
|
||||
m[2][2] = -(zFar + zNear) / deltaZ;
|
||||
m[2][3] = -1.0f;
|
||||
m[3][2] = -2.0f * zNear * zFar / deltaZ;
|
||||
m[3][3] = 0;
|
||||
glMultMatrixf(&m[0][0]);
|
||||
}
|
||||
|
||||
static void normalize(GLfloat v[3])
|
||||
{
|
||||
GLfloat r;
|
||||
|
||||
r=(GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
if (r==0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
v[0]/=r;
|
||||
v[1]/=r;
|
||||
v[2]/=r;
|
||||
}
|
||||
|
||||
static void cross(GLfloat v1[3], GLfloat v2[3], GLfloat result[3])
|
||||
{
|
||||
result[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
result[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
result[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY
|
||||
gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx,
|
||||
GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy,
|
||||
GLfloat upz)
|
||||
{
|
||||
GLfloat forward[3], side[3], up[3];
|
||||
GLfloat m[4][4];
|
||||
|
||||
forward[0] = centerx - eyex;
|
||||
forward[1] = centery - eyey;
|
||||
forward[2] = centerz - eyez;
|
||||
|
||||
up[0] = upx;
|
||||
up[1] = upy;
|
||||
up[2] = upz;
|
||||
|
||||
normalize(forward);
|
||||
|
||||
/* Side = forward x up */
|
||||
cross(forward, up, side);
|
||||
normalize(side);
|
||||
|
||||
/* Recompute up as: up = side x forward */
|
||||
cross(side, forward, up);
|
||||
|
||||
__gluMakeIdentityf(&m[0][0]);
|
||||
m[0][0] = side[0];
|
||||
m[1][0] = side[1];
|
||||
m[2][0] = side[2];
|
||||
|
||||
m[0][1] = up[0];
|
||||
m[1][1] = up[1];
|
||||
m[2][1] = up[2];
|
||||
|
||||
m[0][2] = -forward[0];
|
||||
m[1][2] = -forward[1];
|
||||
m[2][2] = -forward[2];
|
||||
|
||||
glMultMatrixf(&m[0][0]);
|
||||
glTranslatef(-eyex, -eyey, -eyez);
|
||||
}
|
||||
|
||||
static void __gluMultMatrixVecf(const GLfloat matrix[16], const GLfloat in[4],
|
||||
GLfloat out[4])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
out[i] = in[0] * matrix[0*4+i] +
|
||||
in[1] * matrix[1*4+i] +
|
||||
in[2] * matrix[2*4+i] +
|
||||
in[3] * matrix[3*4+i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Invert 4x4 matrix.
|
||||
** Contributed by David Moore (See Mesa bug #6748)
|
||||
*/
|
||||
static int __gluInvertMatrixf(const GLfloat m[16], GLfloat invOut[16])
|
||||
{
|
||||
GLfloat inv[16], det;
|
||||
int i;
|
||||
|
||||
inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
|
||||
+ m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
|
||||
inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
|
||||
- m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
|
||||
inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
|
||||
+ m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
|
||||
inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
|
||||
- m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
|
||||
inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
|
||||
- m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
|
||||
inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
|
||||
+ m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
|
||||
inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
|
||||
- m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
|
||||
inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
|
||||
+ m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
|
||||
inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
|
||||
+ m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
|
||||
inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
|
||||
- m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
|
||||
inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
|
||||
+ m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
|
||||
inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
|
||||
- m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
|
||||
inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
|
||||
- m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
|
||||
inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
|
||||
+ m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
|
||||
inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
|
||||
- m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
|
||||
inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
|
||||
+ m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
|
||||
|
||||
det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
|
||||
if (det == 0)
|
||||
return GL_FALSE;
|
||||
|
||||
det=1.0f/det;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
invOut[i] = inv[i] * det;
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
static void __gluMultMatricesf(const GLfloat a[16], const GLfloat b[16],
|
||||
GLfloat r[16])
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
r[i*4+j] = a[i*4+0]*b[0*4+j] +
|
||||
a[i*4+1]*b[1*4+j] +
|
||||
a[i*4+2]*b[2*4+j] +
|
||||
a[i*4+3]*b[3*4+j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLAPI GLint APIENTRY
|
||||
gluProject(GLfloat objx, GLfloat objy, GLfloat objz,
|
||||
const GLfloat modelMatrix[16],
|
||||
const GLfloat projMatrix[16],
|
||||
const GLint viewport[4],
|
||||
GLfloat* winx, GLfloat* winy, GLfloat* winz)
|
||||
{
|
||||
GLfloat in[4];
|
||||
GLfloat out[4];
|
||||
|
||||
in[0]=objx;
|
||||
in[1]=objy;
|
||||
in[2]=objz;
|
||||
in[3]=1.0;
|
||||
__gluMultMatrixVecf(modelMatrix, in, out);
|
||||
__gluMultMatrixVecf(projMatrix, out, in);
|
||||
if (in[3] == 0.0)
|
||||
{
|
||||
return(GL_FALSE);
|
||||
}
|
||||
|
||||
in[0]/=in[3];
|
||||
in[1]/=in[3];
|
||||
in[2]/=in[3];
|
||||
/* Map x, y and z to range 0-1 */
|
||||
in[0]=in[0]*0.5f+0.5f;
|
||||
in[1]=in[1]*0.5f+0.5f;
|
||||
in[2]=in[2]*0.5f+0.5f;
|
||||
|
||||
/* Map x,y to viewport */
|
||||
in[0]=in[0] * viewport[2] + viewport[0];
|
||||
in[1]=in[1] * viewport[3] + viewport[1];
|
||||
|
||||
*winx=in[0];
|
||||
*winy=in[1];
|
||||
*winz=in[2];
|
||||
|
||||
return(GL_TRUE);
|
||||
}
|
||||
|
||||
GLAPI GLint APIENTRY
|
||||
gluUnProject(GLfloat winx, GLfloat winy, GLfloat winz,
|
||||
const GLfloat modelMatrix[16],
|
||||
const GLfloat projMatrix[16],
|
||||
const GLint viewport[4],
|
||||
GLfloat* objx, GLfloat* objy, GLfloat* objz)
|
||||
{
|
||||
GLfloat finalMatrix[16];
|
||||
GLfloat in[4];
|
||||
GLfloat out[4];
|
||||
|
||||
__gluMultMatricesf(modelMatrix, projMatrix, finalMatrix);
|
||||
if (!__gluInvertMatrixf(finalMatrix, finalMatrix))
|
||||
{
|
||||
return(GL_FALSE);
|
||||
}
|
||||
|
||||
in[0]=winx;
|
||||
in[1]=winy;
|
||||
in[2]=winz;
|
||||
in[3]=1.0;
|
||||
|
||||
/* Map x and y from window coordinates */
|
||||
in[0] = (in[0] - viewport[0]) / viewport[2];
|
||||
in[1] = (in[1] - viewport[1]) / viewport[3];
|
||||
|
||||
/* Map to range -1 to 1 */
|
||||
in[0] = in[0] * 2 - 1;
|
||||
in[1] = in[1] * 2 - 1;
|
||||
in[2] = in[2] * 2 - 1;
|
||||
|
||||
__gluMultMatrixVecf(finalMatrix, in, out);
|
||||
if (out[3] == 0.0)
|
||||
{
|
||||
return(GL_FALSE);
|
||||
}
|
||||
|
||||
out[0] /= out[3];
|
||||
out[1] /= out[3];
|
||||
out[2] /= out[3];
|
||||
*objx = out[0];
|
||||
*objy = out[1];
|
||||
*objz = out[2];
|
||||
|
||||
return(GL_TRUE);
|
||||
}
|
||||
|
||||
GLAPI GLint APIENTRY
|
||||
gluUnProject4(GLfloat winx, GLfloat winy, GLfloat winz, GLfloat clipw,
|
||||
const GLfloat modelMatrix[16],
|
||||
const GLfloat projMatrix[16],
|
||||
const GLint viewport[4],
|
||||
GLclampf nearVal, GLclampf farVal,
|
||||
GLfloat *objx, GLfloat *objy, GLfloat *objz,
|
||||
GLfloat *objw)
|
||||
{
|
||||
GLfloat finalMatrix[16];
|
||||
GLfloat in[4];
|
||||
GLfloat out[4];
|
||||
|
||||
__gluMultMatricesf(modelMatrix, projMatrix, finalMatrix);
|
||||
if (!__gluInvertMatrixf(finalMatrix, finalMatrix))
|
||||
{
|
||||
return(GL_FALSE);
|
||||
}
|
||||
|
||||
in[0]=winx;
|
||||
in[1]=winy;
|
||||
in[2]=winz;
|
||||
in[3]=clipw;
|
||||
|
||||
/* Map x and y from window coordinates */
|
||||
in[0] = (in[0] - viewport[0]) / viewport[2];
|
||||
in[1] = (in[1] - viewport[1]) / viewport[3];
|
||||
in[2] = (in[2] - nearVal) / (farVal - nearVal);
|
||||
|
||||
/* Map to range -1 to 1 */
|
||||
in[0] = in[0] * 2 - 1;
|
||||
in[1] = in[1] * 2 - 1;
|
||||
in[2] = in[2] * 2 - 1;
|
||||
|
||||
__gluMultMatrixVecf(finalMatrix, in, out);
|
||||
if (out[3] == 0.0)
|
||||
{
|
||||
return(GL_FALSE);
|
||||
}
|
||||
|
||||
*objx = out[0];
|
||||
*objy = out[1];
|
||||
*objz = out[2];
|
||||
*objw = out[3];
|
||||
|
||||
return(GL_TRUE);
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY
|
||||
gluPickMatrix(GLfloat x, GLfloat y, GLfloat deltax, GLfloat deltay,
|
||||
GLint viewport[4])
|
||||
{
|
||||
if (deltax <= 0 || deltay <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Translate and scale the picked region to the entire window */
|
||||
glTranslatef((viewport[2] - 2 * (x - viewport[0])) / deltax,
|
||||
(viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
|
||||
glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __GLUES_PROJECT_H__
|
||||
#define __GLUES_PROJECT_H__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
GLAPI void APIENTRY gluOrtho2D(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top);
|
||||
GLAPI void APIENTRY gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
|
||||
GLAPI void APIENTRY gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
|
||||
GLfloat centerx, GLfloat centery, GLfloat centerz,
|
||||
GLfloat upx, GLfloat upy, GLfloat upz);
|
||||
GLAPI GLint APIENTRY gluProject(GLfloat objx, GLfloat objy, GLfloat objz,
|
||||
const GLfloat modelMatrix[16], const GLfloat projMatrix[16],
|
||||
const GLint viewport[4], GLfloat* winx, GLfloat* winy, GLfloat* winz);
|
||||
GLAPI GLint APIENTRY gluUnProject(GLfloat winx, GLfloat winy, GLfloat winz,
|
||||
const GLfloat modelMatrix[16], const GLfloat projMatrix[16],
|
||||
const GLint viewport[4], GLfloat* objx, GLfloat* objy, GLfloat* objz);
|
||||
GLAPI GLint APIENTRY gluUnProject4(GLfloat winx, GLfloat winy, GLfloat winz, GLfloat clipw,
|
||||
const GLfloat modelMatrix[16], const GLfloat projMatrix[16],
|
||||
const GLint viewport[4], GLclampf nearVal, GLclampf farVal,
|
||||
GLfloat* objx, GLfloat* objy, GLfloat* objz, GLfloat* objw);
|
||||
GLAPI void APIENTRY gluPickMatrix(GLfloat x, GLfloat y, GLfloat deltax, GLfloat deltay, GLint viewport[4]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GLUES_PROJECT_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __GLUES_QUAD_H__
|
||||
#define __GLUES_QUAD_H__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
/* QuadricDrawStyle */
|
||||
#define GLU_POINT 100010
|
||||
#define GLU_LINE 100011
|
||||
#define GLU_FILL 100012
|
||||
#define GLU_SILHOUETTE 100013
|
||||
|
||||
/* QuadricCallback */
|
||||
#define GLU_ERROR 100103
|
||||
|
||||
/* QuadricNormal */
|
||||
#define GLU_SMOOTH 100000
|
||||
#define GLU_FLAT 100001
|
||||
#define GLU_NONE 100002
|
||||
|
||||
/* QuadricOrientation */
|
||||
#define GLU_OUTSIDE 100020
|
||||
#define GLU_INSIDE 100021
|
||||
|
||||
#ifdef __cplusplus
|
||||
class GLUquadric;
|
||||
#else
|
||||
typedef struct GLUquadric GLUquadric;
|
||||
#endif
|
||||
|
||||
typedef GLUquadric GLUquadricObj;
|
||||
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif /* APIENTRYP */
|
||||
|
||||
/* Internal convenience typedefs */
|
||||
typedef void (APIENTRYP _GLUfuncptr)();
|
||||
|
||||
GLAPI GLUquadric* APIENTRY gluNewQuadric(void);
|
||||
GLAPI void APIENTRY gluDeleteQuadric(GLUquadric* state);
|
||||
GLAPI void APIENTRY gluQuadricCallback(GLUquadric* qobj, GLenum which,
|
||||
_GLUfuncptr fn);
|
||||
GLAPI void APIENTRY gluQuadricNormals(GLUquadric* qobj, GLenum normals);
|
||||
GLAPI void APIENTRY gluQuadricTexture(GLUquadric* qobj, GLboolean textureCoords);
|
||||
GLAPI void APIENTRY gluQuadricOrientation(GLUquadric* qobj, GLenum orientation);
|
||||
GLAPI void APIENTRY gluQuadricDrawStyle(GLUquadric* qobj, GLenum drawStyle);
|
||||
GLAPI void APIENTRY gluCylinder(GLUquadric* qobj, GLfloat baseRadius,
|
||||
GLfloat topRadius, GLfloat height,
|
||||
GLint slices, GLint stacks);
|
||||
GLAPI void APIENTRY gluDisk(GLUquadric* qobj, GLfloat innerRadius,
|
||||
GLfloat outerRadius, GLint slices, GLint loops);
|
||||
GLAPI void APIENTRY gluPartialDisk(GLUquadric* qobj, GLfloat innerRadius,
|
||||
GLfloat outerRadius, GLint slices,
|
||||
GLint loops, GLfloat startAngle,
|
||||
GLfloat sweepAngle);
|
||||
GLAPI void APIENTRY gluSphere(GLUquadric* qobj, GLfloat radius, GLint slices,
|
||||
GLint stacks);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GLUES_QUAD_H__ */
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "glues_registry.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable: 4996)
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static const GLubyte versionString[]="1.3";
|
||||
static const GLubyte extensionString[]="";
|
||||
|
||||
GLAPI const GLubyte* APIENTRY gluGetString(GLenum name)
|
||||
{
|
||||
if (name==GLU_VERSION)
|
||||
{
|
||||
return versionString;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name==GLU_EXTENSIONS)
|
||||
{
|
||||
return extensionString;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* extName is an extension name.
|
||||
* extString is a string of extensions separated by blank(s). There may or
|
||||
* may not be leading or trailing blank(s) in extString.
|
||||
* This works in cases of extensions being prefixes of another like
|
||||
* GL_EXT_texture and GL_EXT_texture3D.
|
||||
* Returns GL_TRUE if extName is found otherwise it returns GL_FALSE.
|
||||
*/
|
||||
GLAPI GLboolean APIENTRY gluCheckExtension(const GLubyte* extName, const GLubyte* extString)
|
||||
{
|
||||
GLboolean flag=GL_FALSE;
|
||||
char* word;
|
||||
char* lookHere;
|
||||
char* deleteThis;
|
||||
|
||||
if (extString==NULL)
|
||||
{
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
deleteThis=lookHere=(char*)malloc(strlen((const char*)extString)+1);
|
||||
if (lookHere==NULL)
|
||||
{
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
/* strtok() will modify string, so copy it somewhere */
|
||||
strcpy(lookHere,(const char*)extString);
|
||||
|
||||
while ((word=strtok(lookHere, " "))!=NULL)
|
||||
{
|
||||
if (strcmp(word,(const char*)extName)==0)
|
||||
{
|
||||
flag=GL_TRUE;
|
||||
break;
|
||||
}
|
||||
lookHere=NULL; /* get next token */
|
||||
}
|
||||
free((void*)deleteThis);
|
||||
|
||||
return flag;
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* OpenGL ES CM 1.0 port of part of GLU by Mike Gorchak <mike@malva.ua>
|
||||
*/
|
||||
|
||||
#ifndef __GLUES_REGISTRY_H__
|
||||
#define __GLUES_REGISTRY_H__
|
||||
|
||||
#if defined(__USE_SDL_GLES__)
|
||||
#include <SDL/SDL_opengles.h>
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GL_API
|
||||
#endif
|
||||
#elif defined (__QNXNTO__)
|
||||
#include <GLES/gl.h>
|
||||
#elif defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
||||
/* mainly for PowerVR OpenGL ES 1.x win32 emulator */
|
||||
#include <GLES\gl.h>
|
||||
#undef APIENTRY
|
||||
#define APIENTRY
|
||||
#if defined(GLUES_EXPORTS)
|
||||
#define GLAPI __declspec(dllexport)
|
||||
#else
|
||||
#define GLAPI __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#define APIENTRY
|
||||
#define GLAPI
|
||||
#else
|
||||
#error "Platform is unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Version */
|
||||
#define GLU_VERSION_1_1 0x00000001
|
||||
#define GLU_VERSION_1_2 0x00000001
|
||||
#define GLU_VERSION_1_3 0x00000001
|
||||
|
||||
/* StringName */
|
||||
#define GLU_VERSION 100800
|
||||
#define GLU_EXTENSIONS 100801
|
||||
|
||||
GLAPI const GLubyte* APIENTRY gluGetString(GLenum name);
|
||||
GLAPI GLboolean APIENTRY gluCheckExtension(const GLubyte* extName, const GLubyte* extString);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GLUES_REGISTRY_H__ */
|
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
*/
|
||||
|
||||
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
|
|
@ -1,228 +0,0 @@
|
|||
/*
|
||||
*/
|
||||
|
||||
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.
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* 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 /* __dict_list_h_ */
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
DictNode* 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;
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* 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 /* __dict_list_h_ */
|
|
@ -1,325 +0,0 @@
|
|||
/*
|
||||
* 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 <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);
|
||||
}
|
||||
|
||||
GLfloat __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).
|
||||
*/
|
||||
GLfloat 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;
|
||||
}
|
||||
|
||||
GLfloat __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.
|
||||
*/
|
||||
GLfloat 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.
|
||||
*/
|
||||
|
||||
GLfloat __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).
|
||||
*/
|
||||
GLfloat 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;
|
||||
}
|
||||
|
||||
GLfloat __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.
|
||||
*/
|
||||
GLfloat 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;
|
||||
|
||||
GLfloat Interpolate(GLfloat a, GLfloat x, GLfloat b, GLfloat y)
|
||||
{
|
||||
printf("*********************%d\n",RandomInterpolate);
|
||||
if (RandomInterpolate)
|
||||
{
|
||||
a=1.2*drand48()-0.1f;
|
||||
a=(a<0) ? 0 : ((a>1) ? 1 : a);
|
||||
b=1.0f-a;
|
||||
}
|
||||
|
||||
return RealInterpolate(a, x, b, y);
|
||||
}
|
||||
|
||||
#endif /* FOR_TRITE_TEST_PROGRAM */
|
||||
|
||||
#define Swap(a, b) if (1) { GLUvertex* t=a; a=b; b=t; } else
|
||||
|
||||
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.
|
||||
*/
|
||||
{
|
||||
GLfloat 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* 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);
|
||||
GLfloat __gl_edgeEval(GLUvertex* u, GLUvertex* v, GLUvertex* w);
|
||||
GLfloat __gl_edgeSign(GLUvertex* u, GLUvertex* v, GLUvertex* w);
|
||||
GLfloat __gl_transEval(GLUvertex* u, GLUvertex* v, GLUvertex* w);
|
||||
GLfloat __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 /* __geom_h_ */
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* 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 /* MEMORY_DEBUG */
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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 int __gl_memInit(size_t);
|
||||
|
||||
#ifndef MEMORY_DEBUG
|
||||
#define memAlloc malloc
|
||||
#else
|
||||
#define memAlloc __gl_memAlloc
|
||||
extern void* __gl_memAlloc(size_t);
|
||||
#endif /* MEMORY_DEBUG */
|
||||
|
||||
#endif /* __memalloc_simple_h_ */
|
|
@ -1,875 +0,0 @@
|
|||
/*
|
||||
* 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 "mesh.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
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;
|
||||
GLUhalfEdge 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;
|
||||
GLUhalfEdge* 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;
|
||||
GLUvertex* 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;
|
||||
GLUface* 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)
|
||||
{
|
||||
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 /* DELETE_BY_ZAPPING */
|
||||
|
||||
/* __gl_meshDeleteMesh(mesh) will free all storage for any valid mesh.
|
||||
*/
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface* f;
|
||||
GLUface* fNext;
|
||||
GLUvertex* v;
|
||||
GLUvertex* vNext;
|
||||
GLUhalfEdge* e;
|
||||
GLUhalfEdge* 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 /* DELETE_BY_ZAPPING */
|
||||
|
||||
#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;
|
||||
GLUface* fPrev;
|
||||
GLUvertex* v;
|
||||
GLUvertex* vPrev;
|
||||
GLUhalfEdge* e;
|
||||
GLUhalfEdge* 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 /* NDEBUG */
|
|
@ -1,269 +0,0 @@
|
|||
/*
|
||||
* 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 "glues.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) */
|
||||
GLfloat coords[3]; /* vertex location in 3D */
|
||||
GLfloat 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 /* __mesh_h_ */
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
* 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 "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "normal.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define Dot(u, v) (u[0]*v[0]+u[1]*v[1]+u[2]*v[2])
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) ((x)<0 ? -(x) : (x))
|
||||
|
||||
static int LongAxis(GLfloat 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, GLfloat norm[3])
|
||||
{
|
||||
GLUvertex* v, *v1, *v2;
|
||||
GLfloat c, tLen2, maxLen2;
|
||||
GLfloat 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)
|
||||
{
|
||||
GLfloat 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 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.0f)
|
||||
#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0f)
|
||||
#else /* FOR_TRITE_TEST_PROGRAM */
|
||||
#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.50941539564955385f /* Pre-normalized */
|
||||
#define S_UNIT_Y 0.86052074622010633f
|
||||
#else /* SLANTED_SWEEP */
|
||||
#define S_UNIT_X 1.0f
|
||||
#define S_UNIT_Y 0.0f
|
||||
#endif /* SLANTED_SWEEP */
|
||||
#endif /* FOR_TRITE_TEST_PROGRAM */
|
||||
|
||||
/* Determine the polygon normal and project vertices onto the plane
|
||||
* of the polygon.
|
||||
*/
|
||||
void __gl_projectPolygon(GLUtesselator* tess)
|
||||
{
|
||||
GLUvertex *v, *vHead=&tess->mesh->vHead;
|
||||
GLfloat norm[3];
|
||||
GLfloat* sUnit;
|
||||
GLfloat* tUnit;
|
||||
int i;
|
||||
int 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 /* FOR_TRITE_TEST_PROGRAM || TRUE_PROJECT */
|
||||
/* 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 /* FOR_TRITE_TEST_PROGRAM || TRUE_PROJECT */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* 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 /* __normal_h_ */
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
long 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 /* __priorityq_heap_h_ */
|
|
@ -1,276 +0,0 @@
|
|||
/*
|
||||
* 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 <limits.h> /* LONG_MAX */
|
||||
#include "priorityq-heap.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#define INIT_SIZE 32
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#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 /* FOR_TRITE_TEST_PROGRAM */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* so that Minimum() returns NULL */
|
||||
pq->nodes[1].handle=1;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
/* restore ptr to free upon return */
|
||||
pq->nodes=saveNodes;
|
||||
return LONG_MAX;
|
||||
}
|
||||
pq->handles=(PQhandleElem*)memRealloc(pq->handles, (size_t)((pq->max+1)*sizeof(pq->handles[0])));
|
||||
if (pq->handles==NULL)
|
||||
{
|
||||
/* restore ptr to free upon return */
|
||||
pq->handles=saveHandles;
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if (pq->freeList==0)
|
||||
{
|
||||
free=curr;
|
||||
}
|
||||
else
|
||||
{
|
||||
free=pq->freeList;
|
||||
pq->freeList=pq->handles[free].node;
|
||||
}
|
||||
|
||||
pq->nodes[curr].handle=free;
|
||||
pq->handles[free].node=curr;
|
||||
pq->handles[free].key=keyNew;
|
||||
|
||||
if (pq->initialized)
|
||||
{
|
||||
FloatUp(pq, curr);
|
||||
}
|
||||
|
||||
assert(free!=LONG_MAX);
|
||||
|
||||
return free;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
PQhandle 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 /* __priorityq_sort_h_ */
|
|
@ -1,316 +0,0 @@
|
|||
/*
|
||||
* 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 <limits.h> /* LONG_MAX */
|
||||
#include "memalloc.h"
|
||||
|
||||
/* Include all the code for the regular heap-based queue here. */
|
||||
|
||||
#include "priorityq-heap.i"
|
||||
|
||||
/* 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->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) if(1) { PQkey* tmp=*a; *a=*b; *b=tmp; } else
|
||||
|
||||
/* really __gl_pqSortInit */
|
||||
int pqInit(PriorityQ* pq)
|
||||
{
|
||||
PQkey**p, **r, **i, **j, *piv;
|
||||
struct
|
||||
{
|
||||
PQkey** p;
|
||||
PQkey** 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)
|
||||
{
|
||||
/* restore ptr to free upon return */
|
||||
pq->keys=saveKey;
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
PQhandle 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 /* __priorityq_sort_h_ */
|
|
@ -1,584 +0,0 @@
|
|||
/*
|
||||
* 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 <assert.h>
|
||||
#include <stddef.h>
|
||||
#include "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "render.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* 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) if (1) \
|
||||
{ \
|
||||
while( (t) != NULL ) \
|
||||
{ \
|
||||
(t)->marked=FALSE; t=(t)->trail; \
|
||||
} \
|
||||
} else /* 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;
|
||||
GLUhalfEdge* eTail;
|
||||
GLUhalfEdge* 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, GLfloat 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;
|
||||
GLfloat 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.0f;
|
||||
}
|
||||
|
||||
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;
|
||||
GLfloat 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;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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 /* __render_h_ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* 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 /* __sweep_h_ */
|
|
@ -1,640 +0,0 @@
|
|||
/*
|
||||
* 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 <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.0f
|
||||
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/*ARGSUSED*/ static void APIENTRY noBegin(GLenum type) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noEdgeFlag(GLboolean boundaryEdge ) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noVertex(void* data) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noEnd(void) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noError(GLenum errnum) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noCombine(GLfloat coords[3], void *data[4],
|
||||
GLfloat weight[4], void **dataOut) {}
|
||||
/*ARGSUSED*/ static void APIENTRY noMesh(GLUmesh* mesh) {}
|
||||
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noBeginData(GLenum type, void* polygonData) {}
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noEdgeFlagData(GLboolean boundaryEdge, void* polygonData) {}
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noVertexData(void* data, void* polygonData) {}
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noEndData(void* polygonData) {}
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noErrorData( GLenum errnum, void* polygonData) {}
|
||||
/*ARGSUSED*/ void APIENTRY __gl_noCombineData(GLfloat 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))))
|
||||
|
||||
GLAPI GLUtesselator* APIENTRY 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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY gluDeleteTess(GLUtesselator* tess)
|
||||
{
|
||||
RequireState(tess, T_DORMANT);
|
||||
memFree(tess);
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY gluTessProperty(GLUtesselator* tess, GLenum which, GLfloat value)
|
||||
{
|
||||
GLenum windingRule;
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case GLU_TESS_TOLERANCE:
|
||||
if (value<0.0f || value>1.0f)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
GLAPI void APIENTRY gluGetTessProperty(GLUtesselator* tess, GLenum which, GLfloat* value)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case GLU_TESS_TOLERANCE:
|
||||
/* tolerance should be in range [0..1] */
|
||||
assert(0.0f<=tess->relTolerance && tess->relTolerance<=1.0f);
|
||||
*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=(GLfloat)tess->windingRule;
|
||||
break;
|
||||
case GLU_TESS_BOUNDARY_ONLY:
|
||||
assert(tess->boundaryOnly==TRUE || tess->boundaryOnly==FALSE);
|
||||
*value=tess->boundaryOnly;
|
||||
break;
|
||||
default:
|
||||
*value=0.0f;
|
||||
CALL_ERROR_OR_ERROR_DATA(GLU_INVALID_ENUM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY gluTessNormal(GLUtesselator* tess, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
tess->normal[0]=x;
|
||||
tess->normal[1]=y;
|
||||
tess->normal[2]=z;
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY gluTessCallback(GLUtesselator* tess, GLenum which, _GLUfuncptr fn)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case GLU_TESS_BEGIN:
|
||||
tess->callBegin=(fn==NULL) ? &noBegin: (void (APIENTRY*)(GLenum))fn;
|
||||
return;
|
||||
case GLU_TESS_BEGIN_DATA:
|
||||
tess->callBeginData=(fn==NULL) ?
|
||||
&__gl_noBeginData: (void (APIENTRY*)(GLenum, void*))fn;
|
||||
return;
|
||||
case GLU_TESS_EDGE_FLAG:
|
||||
tess->callEdgeFlag=(fn==NULL) ? &noEdgeFlag: (void (APIENTRY*)(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 (APIENTRY*)(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 (APIENTRY*)(void*))fn;
|
||||
return;
|
||||
case GLU_TESS_VERTEX_DATA:
|
||||
tess->callVertexData=(fn==NULL) ?
|
||||
&__gl_noVertexData: (void (APIENTRY*)(void*, void*))fn;
|
||||
return;
|
||||
case GLU_TESS_END:
|
||||
tess->callEnd=(fn==NULL) ? &noEnd: (void (APIENTRY*)(void))fn;
|
||||
return;
|
||||
case GLU_TESS_END_DATA:
|
||||
tess->callEndData=(fn==NULL) ? &__gl_noEndData: (void (APIENTRY*)(void*))fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR:
|
||||
tess->callError=(fn==NULL) ? &noError: (void (APIENTRY*)(GLenum))fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR_DATA:
|
||||
tess->callErrorData=(fn==NULL) ? &__gl_noErrorData: (void (APIENTRY*)(GLenum, void*))fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE:
|
||||
tess->callCombine=(fn==NULL) ? &noCombine:
|
||||
(void (APIENTRY*)(GLfloat[3], void*[4], GLfloat[4], void**))fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE_DATA:
|
||||
tess->callCombineData=(fn==NULL) ? &__gl_noCombineData:
|
||||
(void (APIENTRY*)(GLfloat [3], void*[4], GLfloat[4], void**, void*))fn;
|
||||
return;
|
||||
case GLU_TESS_MESH:
|
||||
tess->callMesh=(fn==NULL) ? &noMesh: (void (APIENTRY*)(GLUmesh*))fn;
|
||||
return;
|
||||
default:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int AddVertex(GLUtesselator* tess, GLfloat coords[3], void* data)
|
||||
{
|
||||
GLUhalfEdge* e=NULL;
|
||||
|
||||
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, GLfloat 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 APIENTRY gluTessVertex(GLUtesselator* tess, GLfloat coords[3], void* data)
|
||||
{
|
||||
int i;
|
||||
int tooLarge=FALSE;
|
||||
GLfloat 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);
|
||||
}
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY 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 APIENTRY 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 APIENTRY gluTessEndContour(GLUtesselator* tess)
|
||||
{
|
||||
RequireState(tess, T_IN_CONTOUR);
|
||||
tess->state=T_IN_POLYGON;
|
||||
}
|
||||
|
||||
void APIENTRY 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;
|
||||
}
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Obsolete calls -- for backward compatibility */
|
||||
void APIENTRY gluBeginPolygon(GLUtesselator* tess)
|
||||
{
|
||||
gluTessBeginPolygon(tess, NULL);
|
||||
gluTessBeginContour(tess);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void APIENTRY gluNextContour(GLUtesselator* tess, GLenum type)
|
||||
{
|
||||
gluTessEndContour(tess);
|
||||
gluTessBeginContour(tess);
|
||||
}
|
||||
|
||||
void APIENTRY gluEndPolygon(GLUtesselator* tess)
|
||||
{
|
||||
gluTessEndContour(tess);
|
||||
gluTessEndPolygon(tess);
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
* 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 "glues.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
|
||||
{
|
||||
GLfloat 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 (APIENTRY* callError)(GLenum errnum);
|
||||
|
||||
/*** state needed for projecting onto the sweep plane ***/
|
||||
GLfloat normal[3]; /* user-specified normal (if provided) */
|
||||
GLfloat sUnit[3]; /* unit vector in s-direction (debugging) */
|
||||
GLfloat tUnit[3]; /* unit vector in t-direction (debugging) */
|
||||
|
||||
/*** state needed for the line sweep ***/
|
||||
GLfloat 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 (APIENTRY* callCombine)(GLfloat 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 */
|
||||
/* list of triangles which could not be rendered as strips or fans */
|
||||
GLUface* lonelyTriList;
|
||||
|
||||
void (APIENTRY* callBegin)(GLenum type);
|
||||
void (APIENTRY* callEdgeFlag)(GLboolean boundaryEdge);
|
||||
void (APIENTRY* callVertex)(void* data);
|
||||
void (APIENTRY* callEnd)(void);
|
||||
void (APIENTRY* 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 (APIENTRY* callBeginData)(GLenum type, void* polygonData);
|
||||
void (APIENTRY* callEdgeFlagData)(GLboolean boundaryEdge, void* polygonData);
|
||||
void (APIENTRY* callVertexData)(void* data, void* polygonData);
|
||||
void (APIENTRY* callEndData)(void* polygonData);
|
||||
void (APIENTRY* callErrorData)(GLenum errnum, void *polygonData);
|
||||
void (APIENTRY* callCombineData)(GLfloat 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 */
|
||||
};
|
||||
|
||||
GLAPI void APIENTRY __gl_noBeginData(GLenum type, void* polygonData);
|
||||
GLAPI void APIENTRY __gl_noEdgeFlagData(GLboolean boundaryEdge, void* polygonData);
|
||||
GLAPI void APIENTRY __gl_noVertexData(void* data, void* polygonData);
|
||||
GLAPI void APIENTRY __gl_noEndData(void* polygonData);
|
||||
GLAPI void APIENTRY __gl_noErrorData(GLenum errnum, void* polygonData);
|
||||
GLAPI void APIENTRY __gl_noCombineData(GLfloat 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 /* __tess_h_ */
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* 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 <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;
|
||||
GLUhalfEdge* 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;
|
||||
GLUface* 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;
|
||||
GLUface* 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;
|
||||
GLUhalfEdge* 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;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* 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 /* __tessmono_h_ */
|
Loading…
Reference in a new issue