remove duplicate jni stuff from gdx-android

This commit is contained in:
Hannes Janetzek 2013-07-01 05:15:55 +02:00
parent 75e4d36945
commit d943933416
42 changed files with 0 additions and 17260 deletions

View File

@ -1,38 +0,0 @@
LOCAL_PATH:= $(call my-dir)
# APP_OPTIM := debug
include $(CLEAR_VARS)
# TRILIBDEFS = -DTRILIBRARY -DREDUCED -DCDT_ONLY
LOCAL_CFLAGS := -O -DTRILIBRARY -DREDUCED -DCDT_ONLY -DNO_TIMER -Werror -std=c99
# -DLINUX -> no fpu_control in bionic, needed ?
LOCAL_MODULE := triangle
LOCAL_SRC_FILES := triangle/TriangleJni.c triangle/triangle.c triangle/triangle_dbg.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := glutils
#LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -Werror -O2 -ffast-math -std=c99
LOCAL_SRC_FILES := gl/utils.c
LOCAL_LDLIBS := -llog -lGLESv2
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := tessellate
#LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -Werror -O2 -ffast-math -std=c99
LOCAL_SRC_FILES := tessellate/dict.c tessellate/mesh.c \
tessellate/render.c tessellate/tess.c tessellate/geom.c \
tessellate/memalloc.c tessellate/normal.c \
tessellate/priorityq.c tessellate/sweep.c \
tessellate/tessmono.c tessellate/tessellate.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

View File

@ -1 +0,0 @@
APP_ABI := armeabi armeabi-v7a

View File

@ -1 +0,0 @@
#include <jni.h>

View File

@ -1,469 +0,0 @@
#include <jni.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android/log.h>
#include <stdlib.h>
#include <math.h>
#define JNI(X) JNIEXPORT Java_org_oscim_utils_GlUtils_##X
#define COLOR_R(C) (((C >> 16) & 0xff) / 255.0f)
#define COLOR_G(C) (((C >> 8) & 0xff) / 255.0f)
#define COLOR_B(C) (((C >> 0) & 0xff) / 255.0f)
#define COLOR_A(C) (((C >> 24) & 0xff) / 255.0f)
void JNI(setColor)(JNIEnv *env, jclass* clazz, jint location, jint c, jfloat alpha)
{
if (alpha >= 1)
alpha = COLOR_A(c);
else if (alpha < 0)
alpha = 0;
else
alpha *= COLOR_A(c);
if (alpha == 1)
{
glUniform4f((GLint) location,
(GLfloat) COLOR_R(c),
(GLfloat) COLOR_G(c),
(GLfloat) COLOR_B(c),
(GLfloat) alpha);
}
else
{
glUniform4f((GLint) location,
(GLfloat) (COLOR_R(c) * alpha),
(GLfloat) (COLOR_G(c) * alpha),
(GLfloat) (COLOR_B(c) * alpha),
(GLfloat) alpha);
}
}
void JNI(setColorBlend)(JNIEnv *env, jclass* clazz, jint location, jint c1, jint c2, jfloat mix)
{
float a1 = COLOR_A(c1) * (1 - mix);
float a2 = COLOR_A(c2) * mix;
glUniform4f((GLint) location,
(GLfloat) (COLOR_R(c1) * a1 + COLOR_R(c2) * a2),
(GLfloat) (COLOR_G(c1) * a1 + COLOR_G(c2) * a2),
(GLfloat) (COLOR_B(c1) * a1 + COLOR_B(c2) * a2),
(GLfloat) (a1 + a2));
}
#undef JNI
#define JNI(X) JNIEXPORT Java_org_oscim_utils_Matrix4_##X
#define CAST(x) (float *)(uintptr_t) x
#define MAT_SIZE 16 * sizeof(float)
static const float identity[] =
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
static inline void
multiplyMM(float* r, const float* lhs, const float* rhs);
static inline void
setRotateM(float* rm, int rmOffset, float a, float x, float y, float z);
static inline void
transposeM(float* mTrans, int mTransOffset, float* m, int mOffset);
static inline void
matrix4_proj(float* mat, float* vec);
jlong JNI(alloc)(JNIEnv *env, jclass* clazz)
{
return (long) calloc(16, sizeof(float));
}
jobject JNI(getBuffer)(JNIEnv *env, jclass* clazz,jlong ptr){
return (*env)->NewDirectByteBuffer(env,(char*)(uintptr_t)ptr, 16*sizeof(float));
}
void JNI(delete)(JNIEnv* env, jclass* clazz, jlong ptr)
{
free(CAST(ptr));
}
void JNI(setAsUniform)(JNIEnv* env, jclass* clazz, jlong ptr, jint location)
{
float* m = CAST(ptr);
glUniformMatrix4fv((GLint) location, (GLsizei) 1, (GLboolean) 0, (GLfloat *) m);
}
void JNI(setValueAt)(JNIEnv* env, jclass* clazz, jlong ptr, jint pos, jfloat value)
{
float* m = CAST(ptr);
if (pos > -1 && pos < 16)
m[pos] = value;
}
void JNI(identity)(JNIEnv* env, jclass* clazz, jlong ptr)
{
float* m = CAST(ptr);
memcpy(m, identity, MAT_SIZE);
}
void JNI(setScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat sx, jfloat sy, jfloat sz)
{
float* m = CAST(ptr);
memcpy(m, identity, MAT_SIZE);
m[0] = sx;
m[5] = sy;
m[10] = sz;
}
void JNI(setTranslation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat x, jfloat y, jfloat z)
{
float* m = CAST(ptr);
memcpy(m, identity, MAT_SIZE);
m[12] = x;
m[13] = y;
m[14] = z;
}
void JNI(setRotation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat a, jfloat x, jfloat y, jfloat z)
{
float* m = CAST(ptr);
setRotateM(m, 0, a, x, y, z);
}
void JNI(setTransScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat tx, jfloat ty, jfloat scale)
{
float* m = CAST(ptr);
memcpy(m, identity, MAT_SIZE);
m[0] = scale;
m[5] = scale;
m[12] = tx;
m[13] = ty;
}
// set matrix from float array
void JNI(set)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
{
float* m = CAST(ptr);
float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
memcpy(m, mat, MAT_SIZE);
(*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, JNI_ABORT);
}
// get float array from matrix
void JNI(get)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
{
float* m = CAST(ptr);
float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
memcpy(mat, m, MAT_SIZE);
(*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, 0);
}
void JNI(mul)(JNIEnv* env, jclass* clazz, jlong ptr_a, jlong ptr_b)
{
float* mata = CAST(ptr_a);
float* matb = CAST(ptr_b);
multiplyMM(mata, mata, matb);
}
void JNI(copy)(JNIEnv* env, jclass* clazz, jlong ptr_dst, jlong ptr_src)
{
float* dst = CAST(ptr_dst);
float* src = CAST(ptr_src);
memcpy(dst, src, MAT_SIZE);
}
void JNI(smul)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a, jlong ptr_b)
{
float* matr = CAST(ptr_r);
float* mata = CAST(ptr_a);
float* matb = CAST(ptr_b);
multiplyMM(matr, mata, matb);
}
void JNI(smulrhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_rhs)
{
float* matr = CAST(ptr_r);
float* mata = alloca(16 * sizeof(float));
float* matb = CAST(ptr_rhs);
memcpy(mata, matr, 16 * sizeof(float));
multiplyMM(matr, mata, matb);
}
void JNI(smullhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_lhs)
{
float* matr = CAST(ptr_r);
float* mata = CAST(ptr_lhs);
float* matb = alloca(16 * sizeof(float));
memcpy(matb, matr, 16 * sizeof(float));
multiplyMM(matr, mata, matb);
}
void JNI(strans)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a)
{
float* matr = CAST(ptr_r);
float* mata = CAST(ptr_a);
transposeM(matr, 0, mata, 0);
}
void JNI(prj)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_vec)
{
float* m = CAST(ptr);
float* vec = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_vec, 0);
matrix4_proj(m, vec);
(*env)->ReleasePrimitiveArrayCritical(env, obj_vec, vec, 0);
}
static float someRandomEpsilon = 1.0f / (1 << 11);
void JNI(addDepthOffset)(JNIEnv* env, jclass* clazz, jlong ptr, jint delta)
{
float* m = CAST(ptr);
// from http://www.mathfor3dgameprogramming.com/code/Listing9.1.cpp
// float n = MapViewPosition.VIEW_NEAR;
// float f = MapViewPosition.VIEW_FAR;
// float pz = 1;
// float epsilon = -2.0f * f * n * delta / ((f + n) * pz * (pz + delta));
m[10] *= 1.0f + someRandomEpsilon * delta;
}
/*
* Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// from android/platform_frameworks_base/blob/master/core/jni/android/opengl/util.cpp
#define I(_i, _j) ((_j)+ 4*(_i))
static inline void
multiplyMM(float* r, const float* lhs, const float* rhs)
{
for (int i = 0; i < 4; i++)
{
register const float rhs_i0 = rhs[I(i,0)];
register float ri0 = lhs[I(0,0)] * rhs_i0;
register float ri1 = lhs[I(0,1)] * rhs_i0;
register float ri2 = lhs[I(0,2)] * rhs_i0;
register float ri3 = lhs[I(0,3)] * rhs_i0;
for (int j = 1; j < 4; j++)
{
register const float rhs_ij = rhs[I(i,j)];
ri0 += lhs[I(j,0)] * rhs_ij;
ri1 += lhs[I(j,1)] * rhs_ij;
ri2 += lhs[I(j,2)] * rhs_ij;
ri3 += lhs[I(j,3)] * rhs_ij;
}
r[I(i,0)] = ri0;
r[I(i,1)] = ri1;
r[I(i,2)] = ri2;
r[I(i,3)] = ri3;
}
}
//static inline
//void
//mx4transform(float x, float y, float z, float w, const float* pM, float* pDest)
//{
// pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
// pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
// pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
//
// pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
//}
/**
* Computes the length of a vector
*
* @param x x coordinate of a vector
* @param y y coordinate of a vector
* @param z z coordinate of a vector
* @return the length of a vector
*/
static inline float
length(float x, float y, float z)
{
return (float) sqrt(x * x + y * y + z * z);
}
/**
* Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
* @param rm returns the result
* @param rmOffset index into rm where the result matrix starts
* @param a angle to rotate in degrees
* @param x scale factor x
* @param y scale factor y
* @param z scale factor z
*/
static inline void
setRotateM(float* rm, int rmOffset, float a, float x, float y, float z)
{
rm[rmOffset + 3] = 0;
rm[rmOffset + 7] = 0;
rm[rmOffset + 11] = 0;
rm[rmOffset + 12] = 0;
rm[rmOffset + 13] = 0;
rm[rmOffset + 14] = 0;
rm[rmOffset + 15] = 1;
a *= (float) (M_PI / 180.0f);
float s = (float) sin(a);
float c = (float) cos(a);
if (1.0f == x && 0.0f == y && 0.0f == z)
{
rm[rmOffset + 5] = c;
rm[rmOffset + 10] = c;
rm[rmOffset + 6] = s;
rm[rmOffset + 9] = -s;
rm[rmOffset + 1] = 0;
rm[rmOffset + 2] = 0;
rm[rmOffset + 4] = 0;
rm[rmOffset + 8] = 0;
rm[rmOffset + 0] = 1;
}
else if (0.0f == x && 1.0f == y && 0.0f == z)
{
rm[rmOffset + 0] = c;
rm[rmOffset + 10] = c;
rm[rmOffset + 8] = s;
rm[rmOffset + 2] = -s;
rm[rmOffset + 1] = 0;
rm[rmOffset + 4] = 0;
rm[rmOffset + 6] = 0;
rm[rmOffset + 9] = 0;
rm[rmOffset + 5] = 1;
}
else if (0.0f == x && 0.0f == y && 1.0f == z)
{
rm[rmOffset + 0] = c;
rm[rmOffset + 5] = c;
rm[rmOffset + 1] = s;
rm[rmOffset + 4] = -s;
rm[rmOffset + 2] = 0;
rm[rmOffset + 6] = 0;
rm[rmOffset + 8] = 0;
rm[rmOffset + 9] = 0;
rm[rmOffset + 10] = 1;
}
else
{
float len = length(x, y, z);
if (1.0f != len)
{
float recipLen = 1.0f / len;
x *= recipLen;
y *= recipLen;
z *= recipLen;
}
float nc = 1.0f - c;
float xy = x * y;
float yz = y * z;
float zx = z * x;
float xs = x * s;
float ys = y * s;
float zs = z * s;
rm[rmOffset + 0] = x * x * nc + c;
rm[rmOffset + 4] = xy * nc - zs;
rm[rmOffset + 8] = zx * nc + ys;
rm[rmOffset + 1] = xy * nc + zs;
rm[rmOffset + 5] = y * y * nc + c;
rm[rmOffset + 9] = yz * nc - xs;
rm[rmOffset + 2] = zx * nc - ys;
rm[rmOffset + 6] = yz * nc + xs;
rm[rmOffset + 10] = z * z * nc + c;
}
}
/**
* Transposes a 4 x 4 matrix.
*
* @param mTrans the array that holds the output inverted matrix
* @param mTransOffset an offset into mInv where the inverted matrix is
* stored.
* @param m the input array
* @param mOffset an offset into m where the matrix is stored.
*/
static inline void
transposeM(float* mTrans, int mTransOffset, float* m, int mOffset)
{
for (int i = 0; i < 4; i++)
{
int mBase = i * 4 + mOffset;
mTrans[i + mTransOffset] = m[mBase];
mTrans[i + 4 + mTransOffset] = m[mBase + 1];
mTrans[i + 8 + mTransOffset] = m[mBase + 2];
mTrans[i + 12 + mTransOffset] = m[mBase + 3];
}
}
/*******************************************************************************
* Copyright 2011 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
// from /gdx/src/com/badlogic/gdx/math/Matrix4.java
#define M00 0
#define M01 4
#define M02 8
#define M03 12
#define M10 1
#define M11 5
#define M12 9
#define M13 13
#define M20 2
#define M21 6
#define M22 10
#define M23 14
#define M30 3
#define M31 7
#define M32 11
#define M33 15
static inline void
matrix4_proj(float* mat, float* vec)
{
float inv_w = 1.0f / (vec[0] * mat[M30] + vec[1] * mat[M31] + vec[2] * mat[M32] + mat[M33]);
float x = (vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02] + mat[M03]) * inv_w;
float y = (vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12] + mat[M13]) * inv_w;
float z = (vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22] + mat[M23]) * inv_w;
vec[0] = x;
vec[1] = y;
vec[2] = z;
}

View File

@ -1,37 +0,0 @@
Copyright notice and license for the libtess files (all source files besides
tessellate.[ch] and main.c):
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.
--------------------------------------------------------------------------------
Copyright notice for the other files:
SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
Copyright (C) 2013 AT&T Intellectual Property. All Rights Reserved.

View File

@ -1,2 +0,0 @@
all:
gcc dict.c mesh.c render.c tess.c geom.c memalloc.c normal.c priorityq.c sweep.c tessmono.c tessellate.c main.c -o tessellate

View File

@ -1,18 +0,0 @@
# A minimal, self-contained port of SGI's GLU libtess
Polygon tessellation is a major pain in the neck. Have you ever tried
writing fast and robust code for it? libtess is, to my knowledge, the
only GPL-compatible, liberally-licensed, high-quality polygon
triangulator out there.
This repository includes a self-contained function (tessellate, in
tessellate.c) that you can call to triangulate a polygon that is
potentially self-intersecting, with holes, or with duplicate
vertices. Simple examples of calling the tessellate function directly
are located in main.c.
More interestingly, this repository also includes an
Emscripten-compiled module, _tessellate.js, and a Javascript-friendly
wrapper, in tessellate.js. Simple examples are available under
index.html.

View File

@ -1,100 +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

View File

@ -1,111 +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, *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;
}

View File

@ -1,100 +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

View File

@ -1,264 +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 "gluos.h"
#include <assert.h>
#include "mesh.h"
#include "geom.h"
int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
{
/* Returns TRUE if u is lexicographically <= v. */
return VertLeq( u, v );
}
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
* Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
* If uw is vertical (and thus passes thru v), the result is zero.
*
* The calculation is extremely accurate and stable, even when v
* is very close to u or w. In particular if we set v->t = 0 and
* let r be the negated result (this evaluates (uw)(v->s)), then
* r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
*/
GLdouble gapL, gapR;
assert( VertLeq( u, v ) && VertLeq( v, w ));
gapL = v->s - u->s;
gapR = w->s - v->s;
if( gapL + gapR > 0 ) {
if( gapL < gapR ) {
return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
} else {
return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Returns a number whose sign matches EdgeEval(u,v,w) but which
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
* as v is above, on, or below the edge uw.
*/
GLdouble gapL, gapR;
assert( VertLeq( u, v ) && VertLeq( v, w ));
gapL = v->s - u->s;
gapR = w->s - v->s;
if( gapL + gapR > 0 ) {
return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
}
/* vertical line */
return 0;
}
/***********************************************************************
* Define versions of EdgeSign, EdgeEval with s and t transposed.
*/
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
* Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
* If uw is vertical (and thus passes thru v), the result is zero.
*
* The calculation is extremely accurate and stable, even when v
* is very close to u or w. In particular if we set v->s = 0 and
* let r be the negated result (this evaluates (uw)(v->t)), then
* r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
*/
GLdouble gapL, gapR;
assert( TransLeq( u, v ) && TransLeq( v, w ));
gapL = v->t - u->t;
gapR = w->t - v->t;
if( gapL + gapR > 0 ) {
if( gapL < gapR ) {
return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
} else {
return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Returns a number whose sign matches TransEval(u,v,w) but which
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
* as v is above, on, or below the edge uw.
*/
GLdouble gapL, gapR;
assert( TransLeq( u, v ) && TransLeq( v, w ));
gapL = v->t - u->t;
gapR = w->t - v->t;
if( gapL + gapR > 0 ) {
return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
}
/* vertical line */
return 0;
}
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* For almost-degenerate situations, the results are not reliable.
* Unless the floating-point arithmetic can be performed without
* rounding errors, *any* implementation will give incorrect results
* on some degenerate inputs, so the client must have some way to
* handle this situation.
*/
return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
}
/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
* this in the rare case that one argument is slightly negative.
* The implementation is extremely stable numerically.
* In particular it guarantees that the result r satisfies
* MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
* even when a and b differ greatly in magnitude.
*/
#define RealInterpolate(a,x,b,y) \
(a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
((a <= b) ? ((b == 0) ? ((x+y) / 2) \
: (x + (y-x) * (a/(a+b)))) \
: (y + (x-y) * (b/(a+b)))))
#ifndef FOR_TRITE_TEST_PROGRAM
#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
#else
/* Claim: the ONLY property the sweep algorithm relies on is that
* MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
*/
#include <stdlib.h>
extern int RandomInterpolate;
GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
{
printf("*********************%d\n",RandomInterpolate);
if( RandomInterpolate ) {
a = 1.2 * drand48() - 0.1;
a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
b = 1.0 - a;
}
return RealInterpolate(a,x,b,y);
}
#endif
#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0)
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
GLUvertex *o2, GLUvertex *d2,
GLUvertex *v )
/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
* The computed point is guaranteed to lie in the intersection of the
* bounding rectangles defined by each edge.
*/
{
GLdouble z1, z2;
/* This is certainly not the most efficient way to find the intersection
* of two line segments, but it is very numerically stable.
*
* Strategy: find the two middle vertices in the VertLeq ordering,
* and interpolate the intersection s-value from these. Then repeat
* using the TransLeq ordering to find the intersection t-value.
*/
if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
if( ! VertLeq( o2, d1 )) {
/* Technically, no intersection -- do our best */
v->s = (o2->s + d1->s) / 2;
} else if( VertLeq( d1, d2 )) {
/* Interpolate between o2 and d1 */
z1 = EdgeEval( o1, o2, d1 );
z2 = EdgeEval( o2, d1, d2 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->s = Interpolate( z1, o2->s, z2, d1->s );
} else {
/* Interpolate between o2 and d2 */
z1 = EdgeSign( o1, o2, d1 );
z2 = -EdgeSign( o1, d2, d1 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->s = Interpolate( z1, o2->s, z2, d2->s );
}
/* Now repeat the process for t */
if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
if( ! TransLeq( o2, d1 )) {
/* Technically, no intersection -- do our best */
v->t = (o2->t + d1->t) / 2;
} else if( TransLeq( d1, d2 )) {
/* Interpolate between o2 and d1 */
z1 = TransEval( o1, o2, d1 );
z2 = TransEval( o2, d1, d2 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->t = Interpolate( z1, o2->t, z2, d1->t );
} else {
/* Interpolate between o2 and d2 */
z1 = TransSign( o1, o2, d1 );
z2 = -TransSign( o1, d2, d1 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->t = Interpolate( z1, o2->t, z2, d2->t );
}
}

View File

@ -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 );
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
GLUvertex *o2, GLUvertex *d2,
GLUvertex *v );
#endif

View File

@ -1,356 +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.
*/
#ifndef __glu_h__
#define __glu_h__
#define GLAPIENTRYP *
#define GLAPIENTRY
#define GLAPI
typedef int GLint;
typedef unsigned int GLenum;
typedef unsigned int GLsizei;
typedef float GLfloat;
typedef double GLdouble;
typedef unsigned char GLubyte;
typedef int GLboolean;
typedef void GLvoid;
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_LINE_LOOP 0x0002
#define GL_LINE_STRIP 0x0003
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
// #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
// # undef GLAPI
// # define GLAPI __declspec(dllexport)
// #elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL)
// /* tag specifying we're building for DLL runtime support */
// # undef GLAPI
// # define GLAPI __declspec(dllimport)
// #elif !defined(GLAPI)
// /* for use with static link lib build of Win32 edition only */
// # define GLAPI extern
// #endif /* _STATIC_MESA support */
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************/
/* Extensions */
#define GLU_EXT_object_space_tess 1
#define GLU_EXT_nurbs_tessellator 1
/* 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
/* NurbsDisplay */
/* GLU_FILL */
#define GLU_OUTLINE_POLYGON 100240
#define GLU_OUTLINE_PATCH 100241
/* NurbsCallback */
#define GLU_NURBS_ERROR 100103
#define GLU_ERROR 100103
#define GLU_NURBS_BEGIN 100164
#define GLU_NURBS_BEGIN_EXT 100164
#define GLU_NURBS_VERTEX 100165
#define GLU_NURBS_VERTEX_EXT 100165
#define GLU_NURBS_NORMAL 100166
#define GLU_NURBS_NORMAL_EXT 100166
#define GLU_NURBS_COLOR 100167
#define GLU_NURBS_COLOR_EXT 100167
#define GLU_NURBS_TEXTURE_COORD 100168
#define GLU_NURBS_TEX_COORD_EXT 100168
#define GLU_NURBS_END 100169
#define GLU_NURBS_END_EXT 100169
#define GLU_NURBS_BEGIN_DATA 100170
#define GLU_NURBS_BEGIN_DATA_EXT 100170
#define GLU_NURBS_VERTEX_DATA 100171
#define GLU_NURBS_VERTEX_DATA_EXT 100171
#define GLU_NURBS_NORMAL_DATA 100172
#define GLU_NURBS_NORMAL_DATA_EXT 100172
#define GLU_NURBS_COLOR_DATA 100173
#define GLU_NURBS_COLOR_DATA_EXT 100173
#define GLU_NURBS_TEXTURE_COORD_DATA 100174
#define GLU_NURBS_TEX_COORD_DATA_EXT 100174
#define GLU_NURBS_END_DATA 100175
#define GLU_NURBS_END_DATA_EXT 100175
/* 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
/* NurbsProperty */
#define GLU_AUTO_LOAD_MATRIX 100200
#define GLU_CULLING 100201
#define GLU_SAMPLING_TOLERANCE 100203
#define GLU_DISPLAY_MODE 100204
#define GLU_PARAMETRIC_TOLERANCE 100202
#define GLU_SAMPLING_METHOD 100205
#define GLU_U_STEP 100206
#define GLU_V_STEP 100207
#define GLU_NURBS_MODE 100160
#define GLU_NURBS_MODE_EXT 100160
#define GLU_NURBS_TESSELLATOR 100161
#define GLU_NURBS_TESSELLATOR_EXT 100161
#define GLU_NURBS_RENDERER 100162
#define GLU_NURBS_RENDERER_EXT 100162
/* NurbsSampling */
#define GLU_OBJECT_PARAMETRIC_ERROR 100208
#define GLU_OBJECT_PARAMETRIC_ERROR_EXT 100208
#define GLU_OBJECT_PATH_LENGTH 100209
#define GLU_OBJECT_PATH_LENGTH_EXT 100209
#define GLU_PATH_LENGTH 100215
#define GLU_PARAMETRIC_ERROR 100216
#define GLU_DOMAIN_DISTANCE 100217
/* NurbsTrim */
#define GLU_MAP1_TRIM_2 100210
#define GLU_MAP1_TRIM_3 100211
/* QuadricDrawStyle */
#define GLU_POINT 100010
#define GLU_LINE 100011
#define GLU_FILL 100012
#define GLU_SILHOUETTE 100013
/* QuadricCallback */
/* GLU_ERROR */
/* QuadricNormal */
#define GLU_SMOOTH 100000
#define GLU_FLAT 100001
#define GLU_NONE 100002
/* QuadricOrientation */
#define GLU_OUTSIDE 100020
#define GLU_INSIDE 100021
/* TessCallback */
#define GLU_TESS_BEGIN 100100
#define GLU_BEGIN 100100
#define GLU_TESS_VERTEX 100101
#define GLU_VERTEX 100101
#define GLU_TESS_END 100102
#define GLU_END 100102
#define GLU_TESS_ERROR 100103
#define GLU_TESS_EDGE_FLAG 100104
#define GLU_EDGE_FLAG 100104
#define GLU_TESS_COMBINE 100105
#define GLU_TESS_BEGIN_DATA 100106
#define GLU_TESS_VERTEX_DATA 100107
#define GLU_TESS_END_DATA 100108
#define GLU_TESS_ERROR_DATA 100109
#define GLU_TESS_EDGE_FLAG_DATA 100110
#define GLU_TESS_COMBINE_DATA 100111
/* TessContour */
#define GLU_CW 100120
#define GLU_CCW 100121
#define GLU_INTERIOR 100122
#define GLU_EXTERIOR 100123
#define GLU_UNKNOWN 100124
/* TessProperty */
#define GLU_TESS_WINDING_RULE 100140
#define GLU_TESS_BOUNDARY_ONLY 100141
#define GLU_TESS_TOLERANCE 100142
/* TessError */
#define GLU_TESS_ERROR1 100151
#define GLU_TESS_ERROR2 100152
#define GLU_TESS_ERROR3 100153
#define GLU_TESS_ERROR4 100154
#define GLU_TESS_ERROR5 100155
#define GLU_TESS_ERROR6 100156
#define GLU_TESS_ERROR7 100157
#define GLU_TESS_ERROR8 100158
#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
#define GLU_TESS_MISSING_END_POLYGON 100153
#define GLU_TESS_MISSING_END_CONTOUR 100154
#define GLU_TESS_COORD_TOO_LARGE 100155
#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
/* TessWinding */
#define GLU_TESS_WINDING_ODD 100130
#define GLU_TESS_WINDING_NONZERO 100131
#define GLU_TESS_WINDING_POSITIVE 100132
#define GLU_TESS_WINDING_NEGATIVE 100133
#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
/*************************************************************/
#ifdef __cplusplus
class GLUnurbs;
class GLUquadric;
class GLUtesselator;
#else
typedef struct GLUnurbs GLUnurbs;
typedef struct GLUquadric GLUquadric;
typedef struct GLUtesselator GLUtesselator;
#endif
typedef GLUnurbs GLUnurbsObj;
typedef GLUquadric GLUquadricObj;
typedef GLUtesselator GLUtesselatorObj;
typedef GLUtesselator GLUtriangulatorObj;
#define GLU_TESS_MAX_COORD 1.0e150
/* Internal convenience typedefs */
typedef void (GLAPIENTRYP _GLUfuncptr)(void);
GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
#ifdef __cplusplus
}
#endif
#endif /* __glu_h__ */

View File

@ -1,86 +0,0 @@
/*
** gluos.h - operating system dependencies for GLU
**
*/
#ifdef __VMS
#ifdef __cplusplus
#pragma message disable nocordel
#pragma message disable codeunreachable
#pragma message disable codcauunr
#endif
#endif
#ifdef __WATCOMC__
/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the
* code at the moment, as it is pretty ugly.
*/
#pragma warning 7 10
#pragma warning 13 10
#pragma warning 14 10
#pragma warning 367 10
#pragma warning 379 10
#pragma warning 726 10
#pragma warning 836 10
#endif
#ifdef BUILD_FOR_SNAP
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#elif defined(_WIN32)
#include <stdlib.h> /* For _MAX_PATH definition */
#include <stdio.h>
#include <malloc.h>
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOIME
#define NOMINMAX
#ifdef __MINGW64_VERSION_MAJOR
#undef _WIN32_WINNT
#endif
#ifndef _WIN32_WINNT
/* XXX: Workaround a bug in mingw-w64's headers when NOGDI is set and
* _WIN32_WINNT >= 0x0600 */
#define _WIN32_WINNT 0x0400
#endif
#ifndef STRICT
#define STRICT 1
#endif
#include <windows.h>
/* Disable warnings */
#if defined(_MSC_VER)
#pragma warning(disable : 4101)
#pragma warning(disable : 4244)
#pragma warning(disable : 4761)
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300
#pragma comment(linker, "/OPT:NOWIN98")
#endif
#ifndef WINGDIAPI
#define WINGDIAPI
#endif
#elif defined(__OS2__)
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#define WINGDIAPI
#else
/* Disable Microsoft-specific keywords */
#define GLAPIENTRY
#define WINGDIAPI
#endif

View File

@ -1,54 +0,0 @@
#include "tessellate.h"
#include <stdio.h>
#include <stdlib.h>
void run_example(const double vertices_array[],
const double *contours_array[],
int contours_size)
{
double *coordinates_out;
int *tris_out;
int nverts, ntris, i;
const double *p = vertices_array;
/* const double **contours = contours_array; */
tessellate(&coordinates_out, &nverts,
&tris_out, &ntris,
contours_array, contours_array + contours_size);
for (i=0; i<2 * nverts; ++i) {
fprintf(stdout, "%g ", coordinates_out[i]);
}
fprintf(stdout, "\n");
for (i=0; i<3 * ntris; ++i) {
fprintf(stdout, "%d ", tris_out[i]);
}
fprintf(stdout, "\n");
free(coordinates_out);
if (tris_out)
free(tris_out);
}
int main()
{
double a1[] = { 0, 0, 1, 5, 2, 0, -1, 3, 3, 3 };
const double *c1[] = {a1, a1+10};
int s1 = 2;
run_example(a1, c1, 2);
printf("\n");
double a2[] = { 0, 0, 3, 0, 3, 3, 0, 3,
1, 1, 2, 1, 2, 2, 1, 2 };
const double *c2[] = {a2, a2+8, a2+16};
int s2 = 3;
run_example(a2, c2, s2);
printf("\n");
double a3[] = { 441, 0, 326, 0, 326, 889, 12, 889, 12, 992, 755, 992, 755, 889, 441, 889 };
const double *c3[] = { a3, a3+16 };
int s3 = 2;
run_example(a3, c3, s3);
printf("\n");
return 0;
}

View File

@ -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

View File

@ -1,54 +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 void __gl_memInit( size_t );*/
extern int __gl_memInit( size_t );
#ifndef MEMORY_DEBUG
#define memAlloc malloc
#else
#define memAlloc __gl_memAlloc
extern void * __gl_memAlloc( size_t );
#endif
#endif

View File

@ -1,798 +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 "gluos.h"
#include <stddef.h>
#include <assert.h>
#include "mesh.h"
#include "memalloc.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
static GLUvertex *allocVertex()
{
return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
}
static GLUface *allocFace()
{
return (GLUface *)memAlloc( sizeof( GLUface ));
}
/************************ Utility Routines ************************/
/* Allocate and free half-edges in pairs for efficiency.
* The *only* place that should use this fact is allocation/free.
*/
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
/* MakeEdge creates a new pair of half-edges which form their own loop.
* No vertex or face structures are allocated, but these must be assigned
* before the current edge operation is completed.
*/
static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
{
GLUhalfEdge *e;
GLUhalfEdge *eSym;
GLUhalfEdge *ePrev;
EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
if (pair == NULL) return NULL;
e = &pair->e;
eSym = &pair->eSym;
/* Make sure eNext points to the first edge of the edge pair */
if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
/* Insert in circular doubly-linked list before eNext.
* Note that the prev pointer is stored in Sym->next.
*/
ePrev = eNext->Sym->next;
eSym->next = ePrev;
ePrev->Sym->next = e;
e->next = eNext;
eNext->Sym->next = eSym;
e->Sym = eSym;
e->Onext = e;
e->Lnext = eSym;
e->Org = NULL;
e->Lface = NULL;
e->winding = 0;
e->activeRegion = NULL;
eSym->Sym = e;
eSym->Onext = eSym;
eSym->Lnext = e;
eSym->Org = NULL;
eSym->Lface = NULL;
eSym->winding = 0;
eSym->activeRegion = NULL;
return e;
}
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
* CS348a notes (see mesh.h). Basically it modifies the mesh so that
* a->Onext and b->Onext are exchanged. This can have various effects
* depending on whether a and b belong to different face or vertex rings.
* For more explanation see __gl_meshSplice() below.
*/
static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
{
GLUhalfEdge *aOnext = a->Onext;
GLUhalfEdge *bOnext = b->Onext;
aOnext->Sym->Lnext = b;
bOnext->Sym->Lnext = a;
a->Onext = bOnext;
b->Onext = aOnext;
}
/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
* a place to insert the new vertex in the global vertex list. We insert
* the new vertex *before* vNext so that algorithms which walk the vertex
* list will not see the newly created vertices.
*/
static void MakeVertex( GLUvertex *newVertex,
GLUhalfEdge *eOrig, GLUvertex *vNext )
{
GLUhalfEdge *e;
GLUvertex *vPrev;
GLUvertex *vNew = newVertex;
assert(vNew != NULL);
/* insert in circular doubly-linked list before vNext */
vPrev = vNext->prev;
vNew->prev = vPrev;
vPrev->next = vNew;
vNew->next = vNext;
vNext->prev = vNew;
vNew->anEdge = eOrig;
vNew->data = NULL;
/* leave coords, s, t undefined */
/* fix other edges on this vertex loop */
e = eOrig;
do {
e->Org = vNew;
e = e->Onext;
} while( e != eOrig );
}
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
* a place to insert the new face in the global face list. We insert
* the new face *before* fNext so that algorithms which walk the face
* list will not see the newly created faces.
*/
static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
{
GLUhalfEdge *e;
GLUface *fPrev;
GLUface *fNew = newFace;
assert(fNew != NULL);
/* insert in circular doubly-linked list before fNext */
fPrev = fNext->prev;
fNew->prev = fPrev;
fPrev->next = fNew;
fNew->next = fNext;
fNext->prev = fNew;
fNew->anEdge = eOrig;
fNew->data = NULL;
fNew->trail = NULL;
fNew->marked = FALSE;
/* The new face is marked "inside" if the old one was. This is a
* convenience for the common case where a face has been split in two.
*/
fNew->inside = fNext->inside;
/* fix other edges on this face loop */
e = eOrig;
do {
e->Lface = fNew;
e = e->Lnext;
} while( e != eOrig );
}
/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
* and removes from the global edge list.
*/
static void KillEdge( GLUhalfEdge *eDel )
{
GLUhalfEdge *ePrev, *eNext;
/* Half-edges are allocated in pairs, see EdgePair above */
if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
/* delete from circular doubly-linked list */
eNext = eDel->next;
ePrev = eDel->Sym->next;
eNext->Sym->next = ePrev;
ePrev->Sym->next = eNext;
memFree( eDel );
}
/* KillVertex( vDel ) destroys a vertex and removes it from the global
* vertex list. It updates the vertex loop to point to a given new vertex.
*/
static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
{
GLUhalfEdge *e, *eStart = vDel->anEdge;
GLUvertex *vPrev, *vNext;
/* change the origin of all affected edges */
e = eStart;
do {
e->Org = newOrg;
e = e->Onext;
} while( e != eStart );
/* delete from circular doubly-linked list */
vPrev = vDel->prev;
vNext = vDel->next;
vNext->prev = vPrev;
vPrev->next = vNext;
memFree( vDel );
}
/* KillFace( fDel ) destroys a face and removes it from the global face
* list. It updates the face loop to point to a given new face.
*/
static void KillFace( GLUface *fDel, GLUface *newLface )
{
GLUhalfEdge *e, *eStart = fDel->anEdge;
GLUface *fPrev, *fNext;
/* change the left face of all affected edges */
e = eStart;
do {
e->Lface = newLface;
e = e->Lnext;
} while( e != eStart );
/* delete from circular doubly-linked list */
fPrev = fDel->prev;
fNext = fDel->next;
fNext->prev = fPrev;
fPrev->next = fNext;
memFree( fDel );
}
/****************** Basic Edge Operations **********************/
/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
* The loop consists of the two new half-edges.
*/
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
{
GLUvertex *newVertex1= allocVertex();
GLUvertex *newVertex2= allocVertex();
GLUface *newFace= allocFace();
GLUhalfEdge *e;
/* if any one is null then all get freed */
if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
if (newVertex1 != NULL) memFree(newVertex1);
if (newVertex2 != NULL) memFree(newVertex2);
if (newFace != NULL) memFree(newFace);
return NULL;
}
e = MakeEdge( &mesh->eHead );
if (e == NULL) {
memFree(newVertex1);
memFree(newVertex2);
memFree(newFace);
return NULL;
}
MakeVertex( newVertex1, e, &mesh->vHead );
MakeVertex( newVertex2, e->Sym, &mesh->vHead );
MakeFace( newFace, e, &mesh->fHead );
return e;
}
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
* mesh connectivity and topology. It changes the mesh so that
* eOrg->Onext <- OLD( eDst->Onext )
* eDst->Onext <- OLD( eOrg->Onext )
* where OLD(...) means the value before the meshSplice operation.
*
* This can have two effects on the vertex structure:
* - if eOrg->Org != eDst->Org, the two vertices are merged together
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
*
* Similarly (and independently) for the face structure,
* - if eOrg->Lface == eDst->Lface, one loop is split into two
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
*
* Some special cases:
* If eDst == eOrg, the operation has no effect.
* If eDst == eOrg->Lnext, the new face will have a single edge.
* If eDst == eOrg->Lprev, the old face will have a single edge.
* If eDst == eOrg->Onext, the new vertex will have a single edge.
* If eDst == eOrg->Oprev, the old vertex will have a single edge.
*/
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
{
int joiningLoops = FALSE;
int joiningVertices = FALSE;
if( eOrg == eDst ) return 1;
if( eDst->Org != eOrg->Org ) {
/* We are merging two disjoint vertices -- destroy eDst->Org */
joiningVertices = TRUE;
KillVertex( eDst->Org, eOrg->Org );
}
if( eDst->Lface != eOrg->Lface ) {
/* We are connecting two disjoint loops -- destroy eDst->Lface */
joiningLoops = TRUE;
KillFace( eDst->Lface, eOrg->Lface );
}
/* Change the edge structure */
Splice( eDst, eOrg );
if( ! joiningVertices ) {
GLUvertex *newVertex= allocVertex();
if (newVertex == NULL) return 0;
/* We split one vertex into two -- the new vertex is eDst->Org.
* Make sure the old vertex points to a valid half-edge.
*/
MakeVertex( newVertex, eDst, eOrg->Org );
eOrg->Org->anEdge = eOrg;
}
if( ! joiningLoops ) {
GLUface *newFace= allocFace();
if (newFace == NULL) return 0;
/* We split one loop into two -- the new loop is eDst->Lface.
* Make sure the old face points to a valid half-edge.
*/
MakeFace( newFace, eDst, eOrg->Lface );
eOrg->Lface->anEdge = eOrg;
}
return 1;
}
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
* the newly created loop will contain eDel->Dst. If the deletion of eDel
* would create isolated vertices, those are deleted as well.
*
* This function could be implemented as two calls to __gl_meshSplice
* plus a few calls to memFree, but this would allocate and delete
* unnecessary vertices and faces.
*/
int __gl_meshDelete( GLUhalfEdge *eDel )
{
GLUhalfEdge *eDelSym = eDel->Sym;
int joiningLoops = FALSE;
/* First step: disconnect the origin vertex eDel->Org. We make all
* changes to get a consistent mesh in this "intermediate" state.
*/
if( eDel->Lface != eDel->Rface ) {
/* We are joining two loops into one -- remove the left face */
joiningLoops = TRUE;
KillFace( eDel->Lface, eDel->Rface );
}
if( eDel->Onext == eDel ) {
KillVertex( eDel->Org, NULL );
} else {
/* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
eDel->Rface->anEdge = eDel->Oprev;
eDel->Org->anEdge = eDel->Onext;
Splice( eDel, eDel->Oprev );
if( ! joiningLoops ) {
GLUface *newFace= allocFace();
if (newFace == NULL) return 0;
/* We are splitting one loop into two -- create a new loop for eDel. */
MakeFace( newFace, eDel, eDel->Lface );
}
}
/* Claim: the mesh is now in a consistent state, except that eDel->Org
* may have been deleted. Now we disconnect eDel->Dst.
*/
if( eDelSym->Onext == eDelSym ) {
KillVertex( eDelSym->Org, NULL );
KillFace( eDelSym->Lface, NULL );
} else {
/* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
eDel->Lface->anEdge = eDelSym->Oprev;
eDelSym->Org->anEdge = eDelSym->Onext;
Splice( eDelSym, eDelSym->Oprev );
}
/* Any isolated vertices or faces have already been freed. */
KillEdge( eDel );
return 1;
}
/******************** Other Edge Operations **********************/
/* All these routines can be implemented with the basic edge
* operations above. They are provided for convenience and efficiency.
*/
/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
* eOrg and eNew will have the same left face.
*/
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
{
GLUhalfEdge *eNewSym;
GLUhalfEdge *eNew = MakeEdge( eOrg );
if (eNew == NULL) return NULL;
eNewSym = eNew->Sym;
/* Connect the new edge appropriately */
Splice( eNew, eOrg->Lnext );
/* Set the vertex and face information */
eNew->Org = eOrg->Dst;
{
GLUvertex *newVertex= allocVertex();
if (newVertex == NULL) return NULL;
MakeVertex( newVertex, eNewSym, eNew->Org );
}
eNew->Lface = eNewSym->Lface = eOrg->Lface;
return eNew;
}
/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
* eOrg and eNew will have the same left face.
*/
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
{
GLUhalfEdge *eNew;
GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
if (tempHalfEdge == NULL) return NULL;
eNew = tempHalfEdge->Sym;
/* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
Splice( eOrg->Sym, eOrg->Sym->Oprev );
Splice( eOrg->Sym, eNew );
/* Set the vertex and face information */
eOrg->Dst = eNew->Org;
eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
eNew->Rface = eOrg->Rface;
eNew->winding = eOrg->winding; /* copy old winding information */
eNew->Sym->winding = eOrg->Sym->winding;
return eNew;
}
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
* to eDst->Org, and returns the corresponding half-edge eNew.
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
* loops are merged into one, and the loop eDst->Lface is destroyed.
*
* If (eOrg == eDst), the new face will have only two edges.
* If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
* If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
*/
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
{
GLUhalfEdge *eNewSym;
int joiningLoops = FALSE;
GLUhalfEdge *eNew = MakeEdge( eOrg );
if (eNew == NULL) return NULL;
eNewSym = eNew->Sym;
if( eDst->Lface != eOrg->Lface ) {
/* We are connecting two disjoint loops -- destroy eDst->Lface */
joiningLoops = TRUE;
KillFace( eDst->Lface, eOrg->Lface );
}
/* Connect the new edge appropriately */
Splice( eNew, eOrg->Lnext );
Splice( eNewSym, eDst );
/* Set the vertex and face information */
eNew->Org = eOrg->Dst;
eNewSym->Org = eDst->Org;
eNew->Lface = eNewSym->Lface = eOrg->Lface;
/* Make sure the old face points to a valid half-edge */
eOrg->Lface->anEdge = eNewSym;
if( ! joiningLoops ) {
GLUface *newFace= allocFace();
if (newFace == NULL) return NULL;
/* We split one loop into two -- the new loop is eNew->Lface */
MakeFace( newFace, eNew, eOrg->Lface );
}
return eNew;
}
/******************** Other Operations **********************/
/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
* global face list. All edges of fZap will have a NULL pointer as their
* left face. Any edges which also have a NULL pointer as their right face
* are deleted entirely (along with any isolated vertices this produces).
* An entire mesh can be deleted by zapping its faces, one at a time,
* in any order. Zapped faces cannot be used in further mesh operations!
*/
void __gl_meshZapFace( GLUface *fZap )
{
GLUhalfEdge *eStart = fZap->anEdge;
GLUhalfEdge *e, *eNext, *eSym;
GLUface *fPrev, *fNext;
/* walk around face, deleting edges whose right face is also NULL */
eNext = eStart->Lnext;
do {
e = eNext;
eNext = e->Lnext;
e->Lface = NULL;
if( e->Rface == NULL ) {
/* delete the edge -- see __gl_MeshDelete above */
if( e->Onext == e ) {
KillVertex( e->Org, NULL );
} else {
/* Make sure that e->Org points to a valid half-edge */
e->Org->anEdge = e->Onext;
Splice( e, e->Oprev );
}
eSym = e->Sym;
if( eSym->Onext == eSym ) {
KillVertex( eSym->Org, NULL );
} else {
/* Make sure that eSym->Org points to a valid half-edge */
eSym->Org->anEdge = eSym->Onext;
Splice( eSym, eSym->Oprev );
}
KillEdge( e );
}
} while( e != eStart );
/* delete from circular doubly-linked list */
fPrev = fZap->prev;
fNext = fZap->next;
fNext->prev = fPrev;
fPrev->next = fNext;
memFree( fZap );
}
/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
* and no loops (what we usually call a "face").
*/
GLUmesh *__gl_meshNewMesh( void )
{
GLUvertex *v;
GLUface *f;
GLUhalfEdge *e;
GLUhalfEdge *eSym;
GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
if (mesh == NULL) {
return NULL;
}
v = &mesh->vHead;
f = &mesh->fHead;
e = &mesh->eHead;
eSym = &mesh->eHeadSym;
v->next = v->prev = v;
v->anEdge = NULL;
v->data = NULL;
f->next = f->prev = f;
f->anEdge = NULL;
f->data = NULL;
f->trail = NULL;
f->marked = FALSE;
f->inside = FALSE;
e->next = e;
e->Sym = eSym;
e->Onext = NULL;
e->Lnext = NULL;
e->Org = NULL;
e->Lface = NULL;
e->winding = 0;
e->activeRegion = NULL;
eSym->next = eSym;
eSym->Sym = e;
eSym->Onext = NULL;
eSym->Lnext = NULL;
eSym->Org = NULL;
eSym->Lface = NULL;
eSym->winding = 0;
eSym->activeRegion = NULL;
return mesh;
}
/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
* both meshes, and returns the new mesh (the old meshes are destroyed).
*/
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
{
GLUface *f1 = &mesh1->fHead;
GLUvertex *v1 = &mesh1->vHead;
GLUhalfEdge *e1 = &mesh1->eHead;
GLUface *f2 = &mesh2->fHead;
GLUvertex *v2 = &mesh2->vHead;
GLUhalfEdge *e2 = &mesh2->eHead;
/* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
if( f2->next != f2 ) {
f1->prev->next = f2->next;
f2->next->prev = f1->prev;
f2->prev->next = f1;
f1->prev = f2->prev;
}
if( v2->next != v2 ) {
v1->prev->next = v2->next;
v2->next->prev = v1->prev;
v2->prev->next = v1;
v1->prev = v2->prev;
}
if( e2->next != e2 ) {
e1->Sym->next->Sym->next = e2->next;
e2->next->Sym->next = e1->Sym->next;
e2->Sym->next->Sym->next = e1;
e1->Sym->next = e2->Sym->next;
}
memFree( mesh2 );
return mesh1;
}
#ifdef DELETE_BY_ZAPPING
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*/
void __gl_meshDeleteMesh( GLUmesh *mesh )
{
GLUface *fHead = &mesh->fHead;
while( fHead->next != fHead ) {
__gl_meshZapFace( fHead->next );
}
assert( mesh->vHead.next == &mesh->vHead );
memFree( mesh );
}
#else
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*/
void __gl_meshDeleteMesh( GLUmesh *mesh )
{
GLUface *f, *fNext;
GLUvertex *v, *vNext;
GLUhalfEdge *e, *eNext;
for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
fNext = f->next;
memFree( f );
}
for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
vNext = v->next;
memFree( v );
}
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
/* One call frees both e and e->Sym (see EdgePair above) */
eNext = e->next;
memFree( e );
}
memFree( mesh );
}
#endif
#ifndef NDEBUG
/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
*/
void __gl_meshCheckMesh( GLUmesh *mesh )
{
GLUface *fHead = &mesh->fHead;
GLUvertex *vHead = &mesh->vHead;
GLUhalfEdge *eHead = &mesh->eHead;
GLUface *f, *fPrev;
GLUvertex *v, *vPrev;
GLUhalfEdge *e, *ePrev;
fPrev = fHead;
for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
assert( f->prev == fPrev );
e = f->anEdge;
do {
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
assert( e->Lface == f );
e = e->Lnext;
} while( e != f->anEdge );
}
assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
vPrev = vHead;
for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
assert( v->prev == vPrev );
e = v->anEdge;
do {
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
assert( e->Org == v );
e = e->Onext;
} while( e != v->anEdge );
}
assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
ePrev = eHead;
for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
assert( e->Sym->next == ePrev->Sym );
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Org != NULL );
assert( e->Dst != NULL );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
}
assert( e->Sym->next == ePrev->Sym
&& e->Sym == &mesh->eHeadSym
&& e->Sym->Sym == e
&& e->Org == NULL && e->Dst == NULL
&& e->Lface == NULL && e->Rface == NULL );
}
#endif

View File

@ -1,266 +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 "glu.h"
typedef struct GLUmesh GLUmesh;
typedef struct GLUvertex GLUvertex;
typedef struct GLUface GLUface;
typedef struct GLUhalfEdge GLUhalfEdge;
typedef struct ActiveRegion ActiveRegion; /* Internal data */
/* The mesh structure is similar in spirit, notation, and operations
* to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
* for the manipulation of general subdivisions and the computation of
* Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
* For a simplified description, see the course notes for CS348a,
* "Mathematical Foundations of Computer Graphics", available at the
* Stanford bookstore (and taught during the fall quarter).
* The implementation also borrows a tiny subset of the graph-based approach
* use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
* to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
*
* The fundamental data structure is the "half-edge". Two half-edges
* go together to make an edge, but they point in opposite directions.
* Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
* its origin vertex (Org), the face on its left side (Lface), and the
* adjacent half-edges in the CCW direction around the origin vertex
* (Onext) and around the left face (Lnext). There is also a "next"
* pointer for the global edge list (see below).
*
* The notation used for mesh navigation:
* Sym = the mate of a half-edge (same edge, but opposite direction)
* Onext = edge CCW around origin vertex (keep same origin)
* Dnext = edge CCW around destination vertex (keep same dest)
* Lnext = edge CCW around left face (dest becomes new origin)
* Rnext = edge CCW around right face (origin becomes new dest)
*
* "prev" means to substitute CW for CCW in the definitions above.
*
* The mesh keeps global lists of all vertices, faces, and edges,
* stored as doubly-linked circular lists with a dummy header node.
* The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
*
* The circular edge list is special; since half-edges always occur
* in pairs (e and e->Sym), each half-edge stores a pointer in only
* one direction. Starting at eHead and following the e->next pointers
* will visit each *edge* once (ie. e or e->Sym, but not both).
* e->Sym stores a pointer in the opposite direction, thus it is
* always true that e->Sym->next->Sym->next == e.
*
* Each vertex has a pointer to next and previous vertices in the
* circular list, and a pointer to a half-edge with this vertex as
* the origin (NULL if this is the dummy header). There is also a
* field "data" for client data.
*
* Each face has a pointer to the next and previous faces in the
* circular list, and a pointer to a half-edge with this face as
* the left face (NULL if this is the dummy header). There is also
* a field "data" for client data.
*
* Note that what we call a "face" is really a loop; faces may consist
* of more than one loop (ie. not simply connected), but there is no
* record of this in the data structure. The mesh may consist of
* several disconnected regions, so it may not be possible to visit
* the entire mesh by starting at a half-edge and traversing the edge
* structure.
*
* The mesh does NOT support isolated vertices; a vertex is deleted along
* with its last edge. Similarly when two faces are merged, one of the
* faces is deleted (see __gl_meshDelete below). For mesh operations,
* all face (loop) and vertex pointers must not be NULL. However, once
* mesh manipulation is finished, __gl_MeshZapFace can be used to delete
* faces of the mesh, one at a time. All external faces can be "zapped"
* before the mesh is returned to the client; then a NULL face indicates
* a region which is not part of the output polygon.
*/
struct GLUvertex {
GLUvertex *next; /* next vertex (never NULL) */
GLUvertex *prev; /* previous vertex (never NULL) */
GLUhalfEdge *anEdge; /* a half-edge with this origin */
void *data; /* client's data */
/* Internal data (keep hidden) */
GLdouble coords[3]; /* vertex location in 3D */
GLdouble s, t; /* projection onto the sweep plane */
long pqHandle; /* to allow deletion from priority queue */
};
struct GLUface {
GLUface *next; /* next face (never NULL) */
GLUface *prev; /* previous face (never NULL) */
GLUhalfEdge *anEdge; /* a half edge with this left face */
void *data; /* room for client's data */
/* Internal data (keep hidden) */
GLUface *trail; /* "stack" for conversion to strips */
GLboolean marked; /* flag for conversion to strips */
GLboolean inside; /* this face is in the polygon interior */
};
struct GLUhalfEdge {
GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
GLUhalfEdge *Sym; /* same edge, opposite direction */
GLUhalfEdge *Onext; /* next edge CCW around origin */
GLUhalfEdge *Lnext; /* next edge CCW around left face */
GLUvertex *Org; /* origin vertex (Overtex too long) */
GLUface *Lface; /* left face */
/* Internal data (keep hidden) */
ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
int winding; /* change in winding number when crossing
from the right face to the left face */
};
#define Rface Sym->Lface
#define Dst Sym->Org
#define Oprev Sym->Lnext
#define Lprev Onext->Sym
#define Dprev Lnext->Sym
#define Rprev Sym->Onext
#define Dnext Rprev->Sym /* 3 pointers */
#define Rnext Oprev->Sym /* 3 pointers */
struct GLUmesh {
GLUvertex vHead; /* dummy header for vertex list */
GLUface fHead; /* dummy header for face list */
GLUhalfEdge eHead; /* dummy header for edge list */
GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
};
/* The mesh operations below have three motivations: completeness,
* convenience, and efficiency. The basic mesh operations are MakeEdge,
* Splice, and Delete. All the other edge operations can be implemented
* in terms of these. The other operations are provided for convenience
* and/or efficiency.
*
* When a face is split or a vertex is added, they are inserted into the
* global list *before* the existing vertex or face (ie. e->Org or e->Lface).
* This makes it easier to process all vertices or faces in the global lists
* without worrying about processing the same data twice. As a convenience,
* when a face is split, the "inside" flag is copied from the old face.
* Other internal data (v->data, v->activeRegion, f->data, f->marked,
* f->trail, e->winding) is set to zero.
*
* ********************** Basic Edge Operations **************************
*
* __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
* The loop (face) consists of the two new half-edges.
*
* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
* mesh connectivity and topology. It changes the mesh so that
* eOrg->Onext <- OLD( eDst->Onext )
* eDst->Onext <- OLD( eOrg->Onext )
* where OLD(...) means the value before the meshSplice operation.
*
* This can have two effects on the vertex structure:
* - if eOrg->Org != eDst->Org, the two vertices are merged together
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
*
* Similarly (and independently) for the face structure,
* - if eOrg->Lface == eDst->Lface, one loop is split into two
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
*
* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
* the newly created loop will contain eDel->Dst. If the deletion of eDel
* would create isolated vertices, those are deleted as well.
*
* ********************** Other Edge Operations **************************
*
* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
* eOrg and eNew will have the same left face.
*
* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
* eOrg and eNew will have the same left face.
*
* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
* to eDst->Org, and returns the corresponding half-edge eNew.
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
* loops are merged into one, and the loop eDst->Lface is destroyed.
*
* ************************ Other Operations *****************************
*
* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
* and no loops (what we usually call a "face").
*
* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
* both meshes, and returns the new mesh (the old meshes are destroyed).
*
* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*
* __gl_meshZapFace( fZap ) destroys a face and removes it from the
* global face list. All edges of fZap will have a NULL pointer as their
* left face. Any edges which also have a NULL pointer as their right face
* are deleted entirely (along with any isolated vertices this produces).
* An entire mesh can be deleted by zapping its faces, one at a time,
* in any order. Zapped faces cannot be used in further mesh operations!
*
* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
*/
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
int __gl_meshDelete( GLUhalfEdge *eDel );
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
GLUmesh *__gl_meshNewMesh( void );
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
void __gl_meshDeleteMesh( GLUmesh *mesh );
void __gl_meshZapFace( GLUface *fZap );
#ifdef NDEBUG
#define __gl_meshCheckMesh( mesh )
#else
void __gl_meshCheckMesh( GLUmesh *mesh );
#endif
#endif

View File

@ -1,257 +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 "gluos.h"
#include "mesh.h"
#include "tess.h"
#include "normal.h"
#include <math.h>
#include <assert.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
#if 0
static void Normalize( GLdouble v[3] )
{
GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
assert( len > 0 );
len = sqrt( len );
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
#endif
#undef ABS
#define ABS(x) ((x) < 0 ? -(x) : (x))
static int LongAxis( GLdouble v[3] )
{
int i = 0;
if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
return i;
}
static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
{
GLUvertex *v, *v1, *v2;
GLdouble c, tLen2, maxLen2;
GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
GLUvertex *maxVert[3], *minVert[3];
GLUvertex *vHead = &tess->mesh->vHead;
int i;
maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
for( v = vHead->next; v != vHead; v = v->next ) {
for( i = 0; i < 3; ++i ) {
c = v->coords[i];
if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
}
}
/* Find two vertices separated by at least 1/sqrt(3) of the maximum
* distance between any two vertices
*/
i = 0;
if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
if( minVal[i] >= maxVal[i] ) {
/* All vertices are the same -- normal doesn't matter */
norm[0] = 0; norm[1] = 0; norm[2] = 1;
return;
}
/* Look for a third vertex which forms the triangle with maximum area
* (Length of normal == twice the triangle area)
*/
maxLen2 = 0;
v1 = minVert[i];
v2 = maxVert[i];
d1[0] = v1->coords[0] - v2->coords[0];
d1[1] = v1->coords[1] - v2->coords[1];
d1[2] = v1->coords[2] - v2->coords[2];
for( v = vHead->next; v != vHead; v = v->next ) {
d2[0] = v->coords[0] - v2->coords[0];
d2[1] = v->coords[1] - v2->coords[1];
d2[2] = v->coords[2] - v2->coords[2];
tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
if( tLen2 > maxLen2 ) {
maxLen2 = tLen2;
norm[0] = tNorm[0];
norm[1] = tNorm[1];
norm[2] = tNorm[2];
}
}
if( maxLen2 <= 0 ) {
/* All points lie on a single line -- any decent normal will do */
norm[0] = norm[1] = norm[2] = 0;
norm[LongAxis(d1)] = 1;
}
}
static void CheckOrientation( GLUtesselator *tess )
{
GLdouble area;
GLUface *f, *fHead = &tess->mesh->fHead;
GLUvertex *v, *vHead = &tess->mesh->vHead;
GLUhalfEdge *e;
/* When we compute the normal automatically, we choose the orientation
* so that the sum of the signed areas of all contours is non-negative.
*/
area = 0;
for( f = fHead->next; f != fHead; f = f->next ) {
e = f->anEdge;
if( e->winding <= 0 ) continue;
do {
area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
e = e->Lnext;
} while( e != f->anEdge );
}
if( area < 0 ) {
/* Reverse the orientation by flipping all the t-coordinates */
for( v = vHead->next; v != vHead; v = v->next ) {
v->t = - v->t;
}
tess->tUnit[0] = - tess->tUnit[0];
tess->tUnit[1] = - tess->tUnit[1];
tess->tUnit[2] = - tess->tUnit[2];
}
}
#ifdef FOR_TRITE_TEST_PROGRAM
#include <stdlib.h>
extern int RandomSweep;
#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
#else
#if defined(SLANTED_SWEEP)
/* The "feature merging" is not intended to be complete. There are
* special cases where edges are nearly parallel to the sweep line
* which are not implemented. The algorithm should still behave
* robustly (ie. produce a reasonable tesselation) in the presence
* of such edges, however it may miss features which could have been
* merged. We could minimize this effect by choosing the sweep line
* direction to be something unusual (ie. not parallel to one of the
* coordinate axes).
*/
#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
#define S_UNIT_Y 0.86052074622010633
#else
#define S_UNIT_X 1.0
#define S_UNIT_Y 0.0
#endif
#endif
/* Determine the polygon normal and project vertices onto the plane
* of the polygon.
*/
void __gl_projectPolygon( GLUtesselator *tess )
{
GLUvertex *v, *vHead = &tess->mesh->vHead;
GLdouble norm[3];
GLdouble *sUnit, *tUnit;
int i, computedNormal = FALSE;
norm[0] = tess->normal[0];
norm[1] = tess->normal[1];
norm[2] = tess->normal[2];
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
ComputeNormal( tess, norm );
computedNormal = TRUE;
}
sUnit = tess->sUnit;
tUnit = tess->tUnit;
i = LongAxis( norm );
#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
/* Choose the initial sUnit vector to be approximately perpendicular
* to the normal.
*/
Normalize( norm );
sUnit[i] = 0;
sUnit[(i+1)%3] = S_UNIT_X;
sUnit[(i+2)%3] = S_UNIT_Y;
/* Now make it exactly perpendicular */
w = Dot( sUnit, norm );
sUnit[0] -= w * norm[0];
sUnit[1] -= w * norm[1];
sUnit[2] -= w * norm[2];
Normalize( sUnit );
/* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
Normalize( tUnit );
#else
/* Project perpendicular to a coordinate axis -- better numerically */
sUnit[i] = 0;
sUnit[(i+1)%3] = S_UNIT_X;
sUnit[(i+2)%3] = S_UNIT_Y;
tUnit[i] = 0;
tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
#endif
/* Project the vertices onto the sweep plane */
for( v = vHead->next; v != vHead; v = v->next ) {
v->s = Dot( v->coords, sUnit );
v->t = Dot( v->coords, tUnit );
}
if( computedNormal ) {
CheckOrientation( tess );
}
}

View File

@ -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

View File

@ -1,257 +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 <limits.h>
#include <stddef.h>
#include <assert.h>
#include "priorityq-heap.h"
#include "memalloc.h"
#define INIT_SIZE 32
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifdef FOR_TRITE_TEST_PROGRAM
#define LEQ(x,y) (*pq->leq)(x,y)
#else
/* Violates modularity, but a little faster */
#include "geom.h"
#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
#endif
/* really __gl_pqHeapNewPriorityQ */
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
{
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
if (pq == NULL) return NULL;
pq->size = 0;
pq->max = INIT_SIZE;
pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
if (pq->nodes == NULL) {
memFree(pq);
return NULL;
}
pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
if (pq->handles == NULL) {
memFree(pq->nodes);
memFree(pq);
return NULL;
}
pq->initialized = FALSE;
pq->freeList = 0;
pq->leq = leq;
pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
pq->handles[1].key = NULL;
return pq;
}
/* really __gl_pqHeapDeletePriorityQ */
void pqDeletePriorityQ( PriorityQ *pq )
{
memFree( pq->handles );
memFree( pq->nodes );
memFree( pq );
}
static void FloatDown( PriorityQ *pq, long curr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hCurr, hChild;
long child;
hCurr = n[curr].handle;
for( ;; ) {
child = curr << 1;
if( child < pq->size && LEQ( h[n[child+1].handle].key,
h[n[child].handle].key )) {
++child;
}
assert(child <= pq->max);
hChild = n[child].handle;
if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
n[curr].handle = hCurr;
h[hCurr].node = curr;
break;
}
n[curr].handle = hChild;
h[hChild].node = curr;
curr = child;
}
}
static void FloatUp( PriorityQ *pq, long curr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hCurr, hParent;
long parent;
hCurr = n[curr].handle;
for( ;; ) {
parent = curr >> 1;
hParent = n[parent].handle;
if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
n[curr].handle = hCurr;
h[hCurr].node = curr;
break;
}
n[curr].handle = hParent;
h[hParent].node = curr;
curr = parent;
}
}
/* really __gl_pqHeapInit */
void pqInit( PriorityQ *pq )
{
long i;
/* This method of building a heap is O(n), rather than O(n lg n). */
for( i = pq->size; i >= 1; --i ) {
FloatDown( pq, i );
}
pq->initialized = TRUE;
}
/* really __gl_pqHeapInsert */
/* returns LONG_MAX iff out of memory */
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
{
long curr;
PQhandle free_handle;
curr = ++ pq->size;
if( (curr*2) > pq->max ) {
PQnode *saveNodes= pq->nodes;
PQhandleElem *saveHandles= pq->handles;
/* If the heap overflows, double its size. */
pq->max <<= 1;
pq->nodes = (PQnode *)memRealloc( pq->nodes,
(size_t)
((pq->max + 1) * sizeof( pq->nodes[0] )));
if (pq->nodes == NULL) {
pq->nodes = saveNodes; /* restore ptr to free upon return */
return LONG_MAX;
}
pq->handles = (PQhandleElem *)memRealloc( pq->handles,
(size_t)
((pq->max + 1) *
sizeof( pq->handles[0] )));
if (pq->handles == NULL) {
pq->handles = saveHandles; /* restore ptr to free upon return */
return LONG_MAX;
}
}
if( pq->freeList == 0 ) {
free_handle = curr;
} else {
free_handle = pq->freeList;
pq->freeList = pq->handles[free_handle].node;
}
pq->nodes[curr].handle = free_handle;
pq->handles[free_handle].node = curr;
pq->handles[free_handle].key = keyNew;
if( pq->initialized ) {
FloatUp( pq, curr );
}
assert(free_handle != LONG_MAX);
return free_handle;
}
/* really __gl_pqHeapExtractMin */
PQkey pqExtractMin( PriorityQ *pq )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hMin = n[1].handle;
PQkey min = h[hMin].key;
if( pq->size > 0 ) {
n[1].handle = n[pq->size].handle;
h[n[1].handle].node = 1;
h[hMin].key = NULL;
h[hMin].node = pq->freeList;
pq->freeList = hMin;
if( -- pq->size > 0 ) {
FloatDown( pq, 1 );
}
}
return min;
}
/* really __gl_pqHeapDelete */
void pqDelete( PriorityQ *pq, PQhandle hCurr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
long curr;
assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
curr = h[hCurr].node;
n[curr].handle = n[pq->size].handle;
h[n[curr].handle].node = curr;
if( curr <= -- pq->size ) {
if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
FloatDown( pq, curr );
} else {
FloatUp( pq, curr );
}
}
h[hCurr].key = NULL;
h[hCurr].node = pq->freeList;
pq->freeList = hCurr;
}

View File

@ -1,107 +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, 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

View File

@ -1,117 +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, 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

View File

@ -1,260 +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 "gluos.h"
#include <stddef.h>
#include <assert.h>
#include <limits.h> /* LONG_MAX */
#include "memalloc.h"
/* Include all the code for the regular heap-based queue here. */
#include "priorityq-heap.c"
/* Now redefine all the function names to map to their "Sort" versions. */
#include "priorityq-sort.h"
/* really __gl_pqSortNewPriorityQ */
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
{
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
if (pq == NULL) return NULL;
pq->heap = __gl_pqHeapNewPriorityQ( leq );
if (pq->heap == NULL) {
memFree(pq);
return NULL;
}
pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
if (pq->keys == NULL) {
__gl_pqHeapDeletePriorityQ(pq->heap);
memFree(pq);
return NULL;
}
pq->size = 0;
pq->max = INIT_SIZE;
pq->initialized = FALSE;
pq->leq = leq;
return pq;
}
/* really __gl_pqSortDeletePriorityQ */
void pqDeletePriorityQ( PriorityQ *pq )
{
assert(pq != NULL);
if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
if (pq->order != NULL) memFree( pq->order );
if (pq->keys != NULL) memFree( pq->keys );
memFree( pq );
}
#define LT(x,y) (! LEQ(y,x))
#define GT(x,y) (! LEQ(x,y))
#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
/* really __gl_pqSortInit */
int pqInit( PriorityQ *pq )
{
PQkey **p, **r, **i, **j, *piv;
struct { PQkey **p, **r; } Stack[50], *top = Stack;
unsigned long seed = 2016473283;
/* Create an array of indirect pointers to the keys, so that we
* the handles we have returned are still valid.
*/
/*
pq->order = (PQHeapKey **)memAlloc( (size_t)
(pq->size * sizeof(pq->order[0])) );
*/
pq->order = (PQHeapKey **)memAlloc( (size_t)
((pq->size+1) * sizeof(pq->order[0])) );
/* the previous line is a patch to compensate for the fact that IBM */
/* machines return a null on a malloc of zero bytes (unlike SGI), */
/* so we have to put in this defense to guard against a memory */
/* fault four lines down. from fossum@austin.ibm.com. */
if (pq->order == NULL) return 0;
p = pq->order;
r = p + pq->size - 1;
for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
*i = piv;
}
/* Sort the indirect pointers in descending order,
* using randomized Quicksort
*/
top->p = p; top->r = r; ++top;
while( --top >= Stack ) {
p = top->p;
r = top->r;
while( r > p + 10 ) {
seed = seed * 1539415821 + 1;
i = p + seed % (r - p + 1);
piv = *i;
*i = *p;
*p = piv;
i = p - 1;
j = r + 1;
do {
do { ++i; } while( GT( **i, *piv ));
do { --j; } while( LT( **j, *piv ));
Swap( i, j );
} while( i < j );
Swap( i, j ); /* Undo last swap */
if( i - p < r - j ) {
top->p = j+1; top->r = r; ++top;
r = i-1;
} else {
top->p = p; top->r = i-1; ++top;
p = j+1;
}
}
/* Insertion sort small lists */
for( i = p+1; i <= r; ++i ) {
piv = *i;
for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
*j = *(j-1);
}
*j = piv;
}
}
pq->max = pq->size;
pq->initialized = TRUE;
__gl_pqHeapInit( pq->heap ); /* always succeeds */
#ifndef NDEBUG
p = pq->order;
r = p + pq->size - 1;
for( i = p; i < r; ++i ) {
assert( LEQ( **(i+1), **i ));
}
#endif
return 1;
}
/* really __gl_pqSortInsert */
/* returns LONG_MAX iff out of memory */
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
{
long curr;
if( pq->initialized ) {
return __gl_pqHeapInsert( pq->heap, keyNew );
}
curr = pq->size;
if( ++ pq->size >= pq->max ) {
PQkey *saveKey= pq->keys;
/* If the heap overflows, double its size. */
pq->max <<= 1;
pq->keys = (PQHeapKey *)memRealloc( pq->keys,
(size_t)
(pq->max * sizeof( pq->keys[0] )));
if (pq->keys == NULL) {
pq->keys = saveKey; /* restore ptr to free upon return */
return LONG_MAX;
}
}
assert(curr != LONG_MAX);
pq->keys[curr] = keyNew;
/* Negative handles index the sorted array. */
return -(curr+1);
}
/* really __gl_pqSortExtractMin */
PQkey pqExtractMin( PriorityQ *pq )
{
PQkey sortMin, heapMin;
if( pq->size == 0 ) {
return __gl_pqHeapExtractMin( pq->heap );
}
sortMin = *(pq->order[pq->size-1]);
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
heapMin = __gl_pqHeapMinimum( pq->heap );
if( LEQ( heapMin, sortMin )) {
return __gl_pqHeapExtractMin( pq->heap );
}
}
do {
-- pq->size;
} while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
return sortMin;
}
/* really __gl_pqSortMinimum */
PQkey pqMinimum( PriorityQ *pq )
{
PQkey sortMin, heapMin;
if( pq->size == 0 ) {
return __gl_pqHeapMinimum( pq->heap );
}
sortMin = *(pq->order[pq->size-1]);
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
heapMin = __gl_pqHeapMinimum( pq->heap );
if( LEQ( heapMin, sortMin )) {
return heapMin;
}
}
return sortMin;
}
/* really __gl_pqSortIsEmpty */
int pqIsEmpty( PriorityQ *pq )
{
return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
}
/* really __gl_pqSortDelete */
void pqDelete( PriorityQ *pq, PQhandle curr )
{
if( curr >= 0 ) {
__gl_pqHeapDelete( pq->heap, curr );
return;
}
curr = -(curr+1);
assert( curr < pq->max && pq->keys[curr] != NULL );
pq->keys[curr] = NULL;
while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
-- pq->size;
}
}

View File

@ -1,117 +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, 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

View File

@ -1,502 +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 "gluos.h"
#include <assert.h>
#include <stddef.h>
#include "mesh.h"
#include "tess.h"
#include "render.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* This structure remembers the information we need about a primitive
* to be able to render it later, once we have determined which
* primitive is able to use the most triangles.
*/
struct FaceCount {
long size; /* number of triangles used */
GLUhalfEdge *eStart; /* edge where this primitive starts */
void (*render)(GLUtesselator *, GLUhalfEdge *, long);
/* routine to render this primitive */
};
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
long size );
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
/************************ Strips and Fans decomposition ******************/
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
* fans, strips, and separate triangles. A substantial effort is made
* to use as few rendering primitives as possible (ie. to make the fans
* and strips as large as possible).
*
* The rendering output is provided as callbacks (see the api).
*/
void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
{
GLUface *f;
/* Make a list of separate triangles so we can render them all at once */
tess->lonelyTriList = NULL;
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
f->marked = FALSE;
}
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
/* We examine all faces in an arbitrary order. Whenever we find
* an unprocessed face F, we output a group of faces including F
* whose size is maximum.
*/
if( f->inside && ! f->marked ) {
RenderMaximumFaceGroup( tess, f );
assert( f->marked );
}
}
if( tess->lonelyTriList != NULL ) {
RenderLonelyTriangles( tess, tess->lonelyTriList );
tess->lonelyTriList = NULL;
}
}
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
{
/* We want to find the largest triangle fan or strip of unmarked faces
* which includes the given face fOrig. There are 3 possible fans
* passing through fOrig (one centered at each vertex), and 3 possible
* strips (one for each CCW permutation of the vertices). Our strategy
* is to try all of these, and take the primitive which uses the most
* triangles (a greedy approach).
*/
GLUhalfEdge *e = fOrig->anEdge;
struct FaceCount max, newFace;
max.size = 1;
max.eStart = e;
max.render = &RenderTriangle;
if( ! tess->flagBoundary ) {
newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
}
(*(max.render))( tess, max.eStart, max.size );
}
/* Macros which keep track of faces we have marked temporarily, and allow
* us to backtrack when necessary. With triangle fans, this is not
* really necessary, since the only awkward case is a loop of triangles
* around a single origin vertex. However with strips the situation is
* more complicated, and we need a general tracking method like the
* one here.
*/
#define Marked(f) (! (f)->inside || (f)->marked)
#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
#define FreeTrail(t) do { \
while( (t) != NULL ) { \
(t)->marked = FALSE; t = (t)->trail; \
} \
} while(0) /* absorb trailing semicolon */
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
{
/* eOrig->Lface is the face we want to render. We want to find the size
* of a maximal fan around eOrig->Org. To do this we just walk around
* the origin vertex as far as possible in both directions.
*/
struct FaceCount newFace = { 0, NULL, &RenderFan };
GLUface *trail = NULL;
GLUhalfEdge *e;
for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
AddToTrail( e->Lface, trail );
++newFace.size;
}
for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
AddToTrail( e->Rface, trail );
++newFace.size;
}
newFace.eStart = e;
/*LINTED*/
FreeTrail( trail );
return newFace;
}
#define IsEven(n) (((n) & 1) == 0)
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
{
/* Here we are looking for a maximal strip that contains the vertices
* eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
* reverse, such that all triangles are oriented CCW).
*
* Again we walk forward and backward as far as possible. However for
* strips there is a twist: to get CCW orientations, there must be
* an *even* number of triangles in the strip on one side of eOrig.
* We walk the strip starting on a side with an even number of triangles;
* if both side have an odd number, we are forced to shorten one side.
*/
struct FaceCount newFace = { 0, NULL, &RenderStrip };
long headSize = 0, tailSize = 0;
GLUface *trail = NULL;
GLUhalfEdge *e, *eTail, *eHead;
for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
AddToTrail( e->Lface, trail );
++tailSize;
e = e->Dprev;
if( Marked( e->Lface )) break;
AddToTrail( e->Lface, trail );
}
eTail = e;
for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
AddToTrail( e->Rface, trail );
++headSize;
e = e->Oprev;
if( Marked( e->Rface )) break;
AddToTrail( e->Rface, trail );
}
eHead = e;
newFace.size = tailSize + headSize;
if( IsEven( tailSize )) {
newFace.eStart = eTail->Sym;
} else if( IsEven( headSize )) {
newFace.eStart = eHead;
} else {
/* Both sides have odd length, we must shorten one of them. In fact,
* we must start from eHead to guarantee inclusion of eOrig->Lface.
*/
--newFace.size;
newFace.eStart = eHead->Onext;
}
/*LINTED*/
FreeTrail( trail );
return newFace;
}
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Just add the triangle to a triangle list, so we can render all
* the separate triangles at once.
*/
assert( size == 1 );
AddToTrail( e->Lface, tess->lonelyTriList );
}
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
{
/* Now we render all the separate triangles which could not be
* grouped into a triangle fan or strip.
*/
GLUhalfEdge *e;
int newState;
int edgeState = -1; /* force edge state output for first vertex */
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
for( ; f != NULL; f = f->trail ) {
/* Loop once for each edge (there will always be 3 edges) */
e = f->anEdge;
do {
if( tess->flagBoundary ) {
/* Set the "edge state" to TRUE just before we output the
* first vertex of each edge on the polygon boundary.
*/
newState = ! e->Rface->inside;
if( edgeState != newState ) {
edgeState = newState;
CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
}
}
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
e = e->Lnext;
} while( e != f->anEdge );
}
CALL_END_OR_END_DATA();
}
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Render as many CCW triangles as possible in a fan starting from
* edge "e". The fan *should* contain exactly "size" triangles
* (otherwise we've goofed up somewhere).
*/
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
while( ! Marked( e->Lface )) {
e->Lface->marked = TRUE;
--size;
e = e->Onext;
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
}
assert( size == 0 );
CALL_END_OR_END_DATA();
}
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Render as many CCW triangles as possible in a strip starting from
* edge "e". The strip *should* contain exactly "size" triangles
* (otherwise we've goofed up somewhere).
*/
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
while( ! Marked( e->Lface )) {
e->Lface->marked = TRUE;
--size;
e = e->Dprev;
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
if( Marked( e->Lface )) break;
e->Lface->marked = TRUE;
--size;
e = e->Onext;
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
}
assert( size == 0 );
CALL_END_OR_END_DATA();
}
/************************ Boundary contour decomposition ******************/
/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
* contour for each face marked "inside". The rendering output is
* provided as callbacks (see the api).
*/
void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
{
GLUface *f;
GLUhalfEdge *e;
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
if( f->inside ) {
CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
e = f->anEdge;
do {
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
e = e->Lnext;
} while( e != f->anEdge );
CALL_END_OR_END_DATA();
}
}
}
/************************ Quick-and-dirty decomposition ******************/
#define SIGN_INCONSISTENT 2
static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
/*
* If check==FALSE, we compute the polygon normal and place it in norm[].
* If check==TRUE, we check that each triangle in the fan from v0 has a
* consistent orientation with respect to norm[]. If triangles are
* consistently oriented CCW, return 1; if CW, return -1; if all triangles
* are degenerate return 0; otherwise (no consistent orientation) return
* SIGN_INCONSISTENT.
*/
{
CachedVertex *v0 = tess->cache;
CachedVertex *vn = v0 + tess->cacheCount;
CachedVertex *vc;
GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
int sign = 0;
/* Find the polygon normal. It is important to get a reasonable
* normal even when the polygon is self-intersecting (eg. a bowtie).
* Otherwise, the computed normal could be very tiny, but perpendicular
* to the true plane of the polygon due to numerical noise. Then all
* the triangles would appear to be degenerate and we would incorrectly
* decompose the polygon as a fan (or simply not render it at all).
*
* We use a sum-of-triangles normal algorithm rather than the more
* efficient sum-of-trapezoids method (used in CheckOrientation()
* in normal.c). This lets us explicitly reverse the signed area
* of some triangles to get a reasonable normal in the self-intersecting
* case.
*/
if( ! check ) {
norm[0] = norm[1] = norm[2] = 0.0;
}
vc = v0 + 1;
xc = vc->coords[0] - v0->coords[0];
yc = vc->coords[1] - v0->coords[1];
zc = vc->coords[2] - v0->coords[2];
while( ++vc < vn ) {
xp = xc; yp = yc; zp = zc;
xc = vc->coords[0] - v0->coords[0];
yc = vc->coords[1] - v0->coords[1];
zc = vc->coords[2] - v0->coords[2];
/* Compute (vp - v0) cross (vc - v0) */
n[0] = yp*zc - zp*yc;
n[1] = zp*xc - xp*zc;
n[2] = xp*yc - yp*xc;
dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
if( ! check ) {
/* Reverse the contribution of back-facing triangles to get
* a reasonable normal for self-intersecting polygons (see above)
*/
if( dot >= 0 ) {
norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
} else {
norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
}
} else if( dot != 0 ) {
/* Check the new orientation for consistency with previous triangles */
if( dot > 0 ) {
if( sign < 0 ) return SIGN_INCONSISTENT;
sign = 1;
} else {
if( sign > 0 ) return SIGN_INCONSISTENT;
sign = -1;
}
}
}
return sign;
}
/* __gl_renderCache( tess ) takes a single contour and tries to render it
* as a triangle fan. This handles convex polygons, as well as some
* non-convex polygons if we get lucky.
*
* Returns TRUE if the polygon was successfully rendered. The rendering
* output is provided as callbacks (see the api).
*/
GLboolean __gl_renderCache( GLUtesselator *tess )
{
CachedVertex *v0 = tess->cache;
CachedVertex *vn = v0 + tess->cacheCount;
CachedVertex *vc;
GLdouble norm[3];
int sign;
if( tess->cacheCount < 3 ) {
/* Degenerate contour -- no output */
return TRUE;
}
norm[0] = tess->normal[0];
norm[1] = tess->normal[1];
norm[2] = tess->normal[2];
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
ComputeNormal( tess, norm, FALSE );
}
sign = ComputeNormal( tess, norm, TRUE );
if( sign == SIGN_INCONSISTENT ) {
/* Fan triangles did not have a consistent orientation */
return FALSE;
}
if( sign == 0 ) {
/* All triangles were degenerate */
return TRUE;
}
/* Make sure we do the right thing for each winding rule */
switch( tess->windingRule ) {
case GLU_TESS_WINDING_ODD:
case GLU_TESS_WINDING_NONZERO:
break;
case GLU_TESS_WINDING_POSITIVE:
if( sign < 0 ) return TRUE;
break;
case GLU_TESS_WINDING_NEGATIVE:
if( sign > 0 ) return TRUE;
break;
case GLU_TESS_WINDING_ABS_GEQ_TWO:
return TRUE;
}
CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
: (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
: GL_TRIANGLES );
CALL_VERTEX_OR_VERTEX_DATA( v0->data );
if( sign > 0 ) {
for( vc = v0+1; vc < vn; ++vc ) {
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
}
} else {
for( vc = vn-1; vc > v0; --vc ) {
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
}
}
CALL_END_OR_END_DATA();
return TRUE;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -1,632 +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 "gluos.h"
#include <stddef.h>
#include <assert.h>
#include <setjmp.h>
#include "memalloc.h"
#include "tess.h"
#include "mesh.h"
#include "normal.h"
#include "sweep.h"
#include "tessmono.h"
#include "render.h"
#define GLU_TESS_DEFAULT_TOLERANCE 0.0
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
GLfloat weight[4], void **dataOut ) {}
/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
void *data[4],
GLfloat weight[4],
void **outData,
void *polygonData ) {}
/* Half-edges are allocated in pairs (see mesh.c) */
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
#undef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
MAX(sizeof(GLUvertex),sizeof(GLUface))))
GLUtesselator * GLAPIENTRY
gluNewTess( void )
{
GLUtesselator *tess;
/* Only initialize fields which can be changed by the api. Other fields
* are initialized where they are used.
*/
if (memInit( MAX_FAST_ALLOC ) == 0) {
return 0; /* out of memory */
}
tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
if (tess == NULL) {
return 0; /* out of memory */
}
tess->state = T_DORMANT;
tess->normal[0] = 0;
tess->normal[1] = 0;
tess->normal[2] = 0;
tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
tess->windingRule = GLU_TESS_WINDING_ODD;
tess->flagBoundary = FALSE;
tess->boundaryOnly = FALSE;
tess->callBegin = &noBegin;
tess->callEdgeFlag = &noEdgeFlag;
tess->callVertex = &noVertex;
tess->callEnd = &noEnd;
tess->callError = &noError;
tess->callCombine = &noCombine;
tess->callMesh = &noMesh;
tess->callBeginData= &__gl_noBeginData;
tess->callEdgeFlagData= &__gl_noEdgeFlagData;
tess->callVertexData= &__gl_noVertexData;
tess->callEndData= &__gl_noEndData;
tess->callErrorData= &__gl_noErrorData;
tess->callCombineData= &__gl_noCombineData;
tess->polygonData= NULL;
return tess;
}
static void MakeDormant( GLUtesselator *tess )
{
/* Return the tessellator to its original dormant state. */
if( tess->mesh != NULL ) {
__gl_meshDeleteMesh( tess->mesh );
}
tess->state = T_DORMANT;
tess->lastEdge = NULL;
tess->mesh = NULL;
}
#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
static void GotoState( GLUtesselator *tess, enum TessState newState )
{
while( tess->state != newState ) {
/* We change the current state one level at a time, to get to
* the desired state.
*/
if( tess->state < newState ) {
switch( tess->state ) {
case T_DORMANT:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
gluTessBeginPolygon( tess, NULL );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
gluTessBeginContour( tess );
break;
default:
;
}
} else {
switch( tess->state ) {
case T_IN_CONTOUR:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
gluTessEndContour( tess );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
/* gluTessEndPolygon( tess ) is too much work! */
MakeDormant( tess );
break;
default:
;
}
}
}
}
void GLAPIENTRY
gluDeleteTess( GLUtesselator *tess )
{
RequireState( tess, T_DORMANT );
memFree( tess );
}
void GLAPIENTRY
gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
{
GLenum windingRule;
switch( which ) {
case GLU_TESS_TOLERANCE:
if( value < 0.0 || value > 1.0 ) break;
tess->relTolerance = value;
return;
case GLU_TESS_WINDING_RULE:
windingRule = (GLenum) value;
if( windingRule != value ) break; /* not an integer */
switch( windingRule ) {
case GLU_TESS_WINDING_ODD:
case GLU_TESS_WINDING_NONZERO:
case GLU_TESS_WINDING_POSITIVE:
case GLU_TESS_WINDING_NEGATIVE:
case GLU_TESS_WINDING_ABS_GEQ_TWO:
tess->windingRule = windingRule;
return;
default:
break;
}
case GLU_TESS_BOUNDARY_ONLY:
tess->boundaryOnly = (value != 0);
return;
default:
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
return;
}
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
}
/* Returns tessellator property */
void GLAPIENTRY
gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
{
switch (which) {
case GLU_TESS_TOLERANCE:
/* tolerance should be in range [0..1] */
assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
*value= tess->relTolerance;
break;
case GLU_TESS_WINDING_RULE:
assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
tess->windingRule == GLU_TESS_WINDING_NONZERO ||
tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
*value= tess->windingRule;
break;
case GLU_TESS_BOUNDARY_ONLY:
assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
*value= tess->boundaryOnly;
break;
default:
*value= 0.0;
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
break;
}
} /* gluGetTessProperty() */
void GLAPIENTRY
gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
{
tess->normal[0] = x;
tess->normal[1] = y;
tess->normal[2] = z;
}
void GLAPIENTRY
gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
{
switch( which ) {
case GLU_TESS_BEGIN:
tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
return;
case GLU_TESS_BEGIN_DATA:
tess->callBeginData = (fn == NULL) ?
&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
return;
case GLU_TESS_EDGE_FLAG:
tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
(void (GLAPIENTRY *)(GLboolean)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_EDGE_FLAG_DATA:
tess->callEdgeFlagData= (fn == NULL) ?
&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_VERTEX:
tess->callVertex = (fn == NULL) ? &noVertex :
(void (GLAPIENTRY *)(void *)) fn;
return;
case GLU_TESS_VERTEX_DATA:
tess->callVertexData = (fn == NULL) ?
&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
return;
case GLU_TESS_END:
tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
return;
case GLU_TESS_END_DATA:
tess->callEndData = (fn == NULL) ? &__gl_noEndData :
(void (GLAPIENTRY *)(void *)) fn;
return;
case GLU_TESS_ERROR:
tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
return;
case GLU_TESS_ERROR_DATA:
tess->callErrorData = (fn == NULL) ?
&__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
return;
case GLU_TESS_COMBINE:
tess->callCombine = (fn == NULL) ? &noCombine :
(void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
return;
case GLU_TESS_COMBINE_DATA:
tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
(void (GLAPIENTRY *)(GLdouble [3],
void *[4],
GLfloat [4],
void **,
void *)) fn;
return;
case GLU_TESS_MESH:
tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
return;
default:
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
return;
}
}
static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
{
GLUhalfEdge *e;
e = tess->lastEdge;
if( e == NULL ) {
/* Make a self-loop (one vertex, one edge). */
e = __gl_meshMakeEdge( tess->mesh );
if (e == NULL) return 0;
if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
} else {
/* Create a new vertex and edge which immediately follow e
* in the ordering around the left face.
*/
if (__gl_meshSplitEdge( e ) == NULL) return 0;
e = e->Lnext;
}
/* The new vertex is now e->Org. */
e->Org->data = data;
e->Org->coords[0] = coords[0];
e->Org->coords[1] = coords[1];
e->Org->coords[2] = coords[2];
/* The winding of an edge says how the winding number changes as we
* cross from the edge''s right face to its left face. We add the
* vertices in such an order that a CCW contour will add +1 to
* the winding number of the region inside the contour.
*/
e->winding = 1;
e->Sym->winding = -1;
tess->lastEdge = e;
return 1;
}
static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
{
CachedVertex *v = &tess->cache[tess->cacheCount];
v->data = data;
v->coords[0] = coords[0];
v->coords[1] = coords[1];
v->coords[2] = coords[2];
++tess->cacheCount;
}
static int EmptyCache( GLUtesselator *tess )
{
CachedVertex *v = tess->cache;
CachedVertex *vLast;
tess->mesh = __gl_meshNewMesh();
if (tess->mesh == NULL) return 0;
for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
}
tess->cacheCount = 0;
tess->emptyCache = FALSE;
return 1;
}
void GLAPIENTRY
gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
{
int i, tooLarge = FALSE;
GLdouble x, clamped[3];
RequireState( tess, T_IN_CONTOUR );
if( tess->emptyCache ) {
if ( !EmptyCache( tess ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
tess->lastEdge = NULL;
}
for( i = 0; i < 3; ++i ) {
x = coords[i];
if( x < - GLU_TESS_MAX_COORD ) {
x = - GLU_TESS_MAX_COORD;
tooLarge = TRUE;
}
if( x > GLU_TESS_MAX_COORD ) {
x = GLU_TESS_MAX_COORD;
tooLarge = TRUE;
}
clamped[i] = x;
}
if( tooLarge ) {
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
}
if( tess->mesh == NULL ) {
if( tess->cacheCount < TESS_MAX_CACHE ) {
CacheVertex( tess, clamped, data );
return;
}
if ( !EmptyCache( tess ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
}
if ( !AddVertex( tess, clamped, data ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
}
}
void GLAPIENTRY
gluTessBeginPolygon( GLUtesselator *tess, void *data )
{
RequireState( tess, T_DORMANT );
tess->state = T_IN_POLYGON;
tess->cacheCount = 0;
tess->emptyCache = FALSE;
tess->mesh = NULL;
tess->polygonData= data;
}
void GLAPIENTRY
gluTessBeginContour( GLUtesselator *tess )
{
RequireState( tess, T_IN_POLYGON );
tess->state = T_IN_CONTOUR;
tess->lastEdge = NULL;
if( tess->cacheCount > 0 ) {
/* Just set a flag so we don't get confused by empty contours
* -- these can be generated accidentally with the obsolete
* NextContour() interface.
*/
tess->emptyCache = TRUE;
}
}
void GLAPIENTRY
gluTessEndContour( GLUtesselator *tess )
{
RequireState( tess, T_IN_CONTOUR );
tess->state = T_IN_POLYGON;
}
void GLAPIENTRY
gluTessEndPolygon( GLUtesselator *tess )
{
GLUmesh *mesh;
if (setjmp(tess->env) != 0) {
/* come back here if out of memory */
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
RequireState( tess, T_IN_POLYGON );
tess->state = T_DORMANT;
if( tess->mesh == NULL ) {
if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
/* Try some special code to make the easy cases go quickly
* (eg. convex polygons). This code does NOT handle multiple contours,
* intersections, edge flags, and of course it does not generate
* an explicit mesh either.
*/
if( __gl_renderCache( tess )) {
tess->polygonData= NULL;
return;
}
}
if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
}
/* Determine the polygon normal and project vertices onto the plane
* of the polygon.
*/
__gl_projectPolygon( tess );
/* __gl_computeInterior( tess ) computes the planar arrangement specified
* by the given contours, and further subdivides this arrangement
* into regions. Each region is marked "inside" if it belongs
* to the polygon, according to the rule given by tess->windingRule.
* Each interior region is guaranteed be monotone.
*/
if ( !__gl_computeInterior( tess ) ) {
longjmp(tess->env,1); /* could've used a label */
}
mesh = tess->mesh;
if( ! tess->fatalError ) {
int rc = 1;
/* If the user wants only the boundary contours, we throw away all edges
* except those which separate the interior from the exterior.
* Otherwise we tessellate all the regions marked "inside".
*/
if( tess->boundaryOnly ) {
rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
} else {
rc = __gl_meshTessellateInterior( mesh );
}
if (rc == 0) longjmp(tess->env,1); /* could've used a label */
__gl_meshCheckMesh( mesh );
if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
|| tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
|| tess->callBeginData != &__gl_noBeginData
|| tess->callEndData != &__gl_noEndData
|| tess->callVertexData != &__gl_noVertexData
|| tess->callEdgeFlagData != &__gl_noEdgeFlagData )
{
if( tess->boundaryOnly ) {
__gl_renderBoundary( tess, mesh ); /* output boundary contours */
} else {
__gl_renderMesh( tess, mesh ); /* output strips and fans */
}
}
if( tess->callMesh != &noMesh ) {
/* Throw away the exterior faces, so that all faces are interior.
* This way the user doesn't have to check the "inside" flag,
* and we don't need to even reveal its existence. It also leaves
* the freedom for an implementation to not generate the exterior
* faces in the first place.
*/
__gl_meshDiscardExterior( mesh );
(*tess->callMesh)( mesh ); /* user wants the mesh itself */
tess->mesh = NULL;
tess->polygonData= NULL;
return;
}
}
__gl_meshDeleteMesh( mesh );
tess->polygonData= NULL;
tess->mesh = NULL;
}
/*XXXblythe unused function*/
#if 0
void GLAPIENTRY
gluDeleteMesh( GLUmesh *mesh )
{
__gl_meshDeleteMesh( mesh );
}
#endif
/*******************************************************/
/* Obsolete calls -- for backward compatibility */
void GLAPIENTRY
gluBeginPolygon( GLUtesselator *tess )
{
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
}
/*ARGSUSED*/
void GLAPIENTRY
gluNextContour( GLUtesselator *tess, GLenum type )
{
gluTessEndContour( tess );
gluTessBeginContour( tess );
}
void GLAPIENTRY
gluEndPolygon( GLUtesselator *tess )
{
gluTessEndContour( tess );
gluTessEndPolygon( tess );
}

View File

@ -1,165 +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 "glu.h"
#include <setjmp.h>
#include "mesh.h"
#include "dict.h"
#include "priorityq.h"
/* The begin/end calls must be properly nested. We keep track of
* the current state to enforce the ordering.
*/
enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
/* We cache vertex data for single-contour polygons so that we can
* try a quick-and-dirty decomposition first.
*/
#define TESS_MAX_CACHE 100
typedef struct CachedVertex {
GLdouble coords[3];
void *data;
} CachedVertex;
struct GLUtesselator {
/*** state needed for collecting the input data ***/
enum TessState state; /* what begin/end calls have we seen? */
GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
GLUmesh *mesh; /* stores the input contours, and eventually
the tessellation itself */
void (GLAPIENTRY *callError)( GLenum errnum );
/*** state needed for projecting onto the sweep plane ***/
GLdouble normal[3]; /* user-specified normal (if provided) */
GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
/*** state needed for the line sweep ***/
GLdouble relTolerance; /* tolerance for merging features */
GLenum windingRule; /* rule for determining polygon interior */
GLboolean fatalError; /* fatal error: needed combine callback */
Dict *dict; /* edge dictionary for sweep line */
PriorityQ *pq; /* priority queue of vertex events */
GLUvertex *event; /* current sweep event being processed */
void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
GLfloat weight[4], void **outData );
/*** state needed for rendering callbacks (see render.c) ***/
GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
GLboolean boundaryOnly; /* Extract contours, not triangles */
GLUface *lonelyTriList;
/* list of triangles which could not be rendered as strips or fans */
void (GLAPIENTRY *callBegin)( GLenum type );
void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
void (GLAPIENTRY *callVertex)( void *data );
void (GLAPIENTRY *callEnd)( void );
void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
/*** state needed to cache single-contour polygons for renderCache() */
GLboolean emptyCache; /* empty cache on next vertex() call */
int cacheCount; /* number of cached vertices */
CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
/*** rendering callbacks that also pass polygon data ***/
void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
void *polygonData );
void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
void (GLAPIENTRY *callEndData)( void *polygonData );
void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
GLfloat weight[4], void **outData,
void *polygonData );
jmp_buf env; /* place to jump to when memAllocs fail */
void *polygonData; /* client data for current polygon */
};
void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
void GLAPIENTRY __gl_noEndData( void *polygonData );
void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
GLfloat weight[4], void **outData,
void *polygonData );
#define CALL_BEGIN_OR_BEGIN_DATA(a) \
if (tess->callBeginData != &__gl_noBeginData) \
(*tess->callBeginData)((a),tess->polygonData); \
else (*tess->callBegin)((a));
#define CALL_VERTEX_OR_VERTEX_DATA(a) \
if (tess->callVertexData != &__gl_noVertexData) \
(*tess->callVertexData)((a),tess->polygonData); \
else (*tess->callVertex)((a));
#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
(*tess->callEdgeFlagData)((a),tess->polygonData); \
else (*tess->callEdgeFlag)((a));
#define CALL_END_OR_END_DATA() \
if (tess->callEndData != &__gl_noEndData) \
(*tess->callEndData)(tess->polygonData); \
else (*tess->callEnd)();
#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
if (tess->callCombineData != &__gl_noCombineData) \
(*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
else (*tess->callCombine)((a),(b),(c),(d));
#define CALL_ERROR_OR_ERROR_DATA(a) \
if (tess->callErrorData != &__gl_noErrorData) \
(*tess->callErrorData)((a),tess->polygonData); \
else (*tess->callError)((a));
#endif

View File

@ -1,376 +0,0 @@
#include <jni.h>
#include <string.h>
#include "glu.h"
#include "tess.h"
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
/******************************************************************************/
typedef struct Triangle {
int v[3];
struct Triangle *prev;
} Triangle;
typedef struct Vertex {
double pt[3];
int index;
struct Vertex *prev;
} Vertex;
typedef struct TessContext {
Triangle *latest_t;
int n_tris;
Vertex *v_prev;
Vertex *v_prevprev;
Vertex *latest_v;
GLenum current_mode;
int odd_even_strip;
void (*vertex_cb)(Vertex *, struct TessContext *);
} TessContext;
void skip_vertex(Vertex *v, TessContext *ctx);
/******************************************************************************/
TessContext *new_tess_context()
{
TessContext *result = (TessContext *) malloc(sizeof(struct TessContext));
result->latest_t = NULL;
result->latest_v = NULL;
result->n_tris = 0;
result->v_prev = NULL;
result->v_prevprev = NULL;
result->v_prev = NULL;
result->v_prev = NULL;
result->vertex_cb = &skip_vertex;
result->odd_even_strip = 0;
return result;
}
void destroy_tess_context(TessContext *ctx)
{
free(ctx);
}
Vertex *new_vertex(TessContext *ctx, double x, double y)
{
Vertex *result = (Vertex *) malloc(sizeof(Vertex));
result->prev = ctx->latest_v;
result->pt[0] = x;
result->pt[1] = y;
result->pt[2] = 0;
if (ctx->latest_v == NULL) {
result->index = 0;
}
else {
result->index = ctx->latest_v->index + 1;
}
return ctx->latest_v = result;
}
Triangle *new_triangle(TessContext *ctx, int v1, int v2, int v3)
{
Triangle *result = (Triangle *) malloc(sizeof(Triangle));
result->prev = ctx->latest_t;
result->v[0] = v1;
result->v[1] = v2;
result->v[2] = v3;
ctx->n_tris++;
return ctx->latest_t = result;
}
/******************************************************************************/
void skip_vertex(Vertex *v, TessContext *ctx) {
}
;
void fan_vertex(Vertex *v, TessContext *ctx) {
if (ctx->v_prevprev == NULL) {
ctx->v_prevprev = v;
return;
}
if (ctx->v_prev == NULL) {
ctx->v_prev = v;
return;
}
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
ctx->v_prev = v;
}
void strip_vertex(Vertex *v, TessContext *ctx)
{
if (ctx->v_prev == NULL) {
ctx->v_prev = v;
return;
}
if (ctx->v_prevprev == NULL) {
ctx->v_prevprev = v;
return;
}
if (ctx->odd_even_strip) {
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
}
else {
new_triangle(ctx, ctx->v_prev->index, ctx->v_prevprev->index, v->index);
}
ctx->odd_even_strip = !ctx->odd_even_strip;
ctx->v_prev = ctx->v_prevprev;
ctx->v_prevprev = v;
}
void triangle_vertex(Vertex *v, TessContext *ctx) {
if (ctx->v_prevprev == NULL) {
ctx->v_prevprev = v;
return;
}
if (ctx->v_prev == NULL) {
ctx->v_prev = v;
return;
}
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
ctx->v_prev = ctx->v_prevprev = NULL;
}
void vertex(void *vertex_data, void *poly_data)
{
Vertex *ptr = (Vertex *) vertex_data;
TessContext *ctx = (TessContext *) poly_data;
ctx->vertex_cb(ptr, ctx);
}
void begin(GLenum which, void *poly_data)
{
TessContext *ctx = (TessContext *) poly_data;
ctx->v_prev = ctx->v_prevprev = NULL;
ctx->odd_even_strip = 0;
switch (which) {
case GL_TRIANGLES:
ctx->vertex_cb = &triangle_vertex;
break;
case GL_TRIANGLE_STRIP:
ctx->vertex_cb = &strip_vertex;
break;
case GL_TRIANGLE_FAN:
ctx->vertex_cb = &fan_vertex;
break;
default:
fprintf(stderr, "ERROR, can't handle %d\n", (int) which);
ctx->vertex_cb = &skip_vertex;
break;
}
}
void combine(const GLdouble newVertex[3],
const void *neighborVertex[4],
const GLfloat neighborWeight[4], void **outData, void *polyData)
{
TessContext *ctx = (TessContext *) polyData;
Vertex *result = new_vertex(ctx, newVertex[0], newVertex[1]);
*outData = result;
}
void write_output(TessContext *ctx, float **coordinates_out, int **tris_out, int *vc, int *tc)
{
int n_verts = 1 + ctx->latest_v->index;
*vc = n_verts;
int n_tris_copy = ctx->n_tris;
*tc = ctx->n_tris;
*coordinates_out = malloc(n_verts * sizeof(float) * 2);
*tris_out = (ctx->n_tris ? malloc(ctx->n_tris * sizeof(int) * 3) : NULL);
while (ctx->latest_v) {
(*coordinates_out)[2 * ctx->latest_v->index] = ctx->latest_v->pt[0];
(*coordinates_out)[2 * ctx->latest_v->index + 1] = ctx->latest_v->pt[1];
Vertex *prev = ctx->latest_v->prev;
free(ctx->latest_v);
ctx->latest_v = prev;
}
while (ctx->latest_t) {
(*tris_out)[3 * (n_tris_copy - 1)] = ctx->latest_t->v[0];
(*tris_out)[3 * (n_tris_copy - 1) + 1] = ctx->latest_t->v[1];
(*tris_out)[3 * (n_tris_copy - 1) + 2] = ctx->latest_t->v[2];
Triangle *prev = ctx->latest_t->prev;
free(ctx->latest_t);
ctx->latest_t = prev;
n_tris_copy--;
}
}
TessContext *tessellate(
int *nverts,
int *ntris,
const float **contoursbegin,
const float **contoursend)
{
const float *contourbegin, *contourend;
Vertex *current_vertex;
GLUtesselator *tess;
TessContext *ctx;
tess = gluNewTess();
ctx = new_tess_context();
gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*)()) &vertex);
gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*)()) &begin);
gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*)()) &combine);
gluTessBeginPolygon(tess, ctx);
do {
contourbegin = *contoursbegin++;
contourend = *contoursbegin;
gluTessBeginContour(tess);
while (contourbegin != contourend) {
current_vertex = new_vertex(ctx, contourbegin[0], contourbegin[1]);
contourbegin += 2;
gluTessVertex(tess, current_vertex->pt, current_vertex);
}
gluTessEndContour(tess);
} while (contoursbegin != (contoursend - 1));
gluTessEndPolygon(tess);
//write_output(ctx, verts, tris, nverts, ntris);
//destroy_tess_context(ctx);
gluDeleteTess(tess);
return ctx;
}
#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Tesselate", __VA_ARGS__)
#define CAST_CTX(x) (TessContext *)(uintptr_t) x
void Java_org_oscim_renderer_sublayers_MeshLayer_tessFinish(JNIEnv *env, jclass c,
jlong ptr_context) {
TessContext *ctx = CAST_CTX(ptr_context);
while (ctx->latest_v) {
Vertex *prev = ctx->latest_v->prev;
free(ctx->latest_v);
ctx->latest_v = prev;
}
while (ctx->latest_t) {
Triangle *prev = ctx->latest_t->prev;
free(ctx->latest_t);
ctx->latest_t = prev;
}
destroy_tess_context(ctx);
}
jint Java_org_oscim_renderer_sublayers_MeshLayer_tessGetCoordinates(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_coords, jfloat scale) {
TessContext *ctx = CAST_CTX(ptr_context);
int length = (*env)->GetArrayLength(env, obj_coords);
jshort* coords = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_coords, 0);
if (coords == NULL) {
return 0;
}
int n_verts = 1 + ctx->latest_v->index;
int n_tris_copy = ctx->n_tris;
int cnt = 0;
for (; ctx->latest_v && cnt < length; cnt += 2) {
coords[cnt + 0] = (ctx->latest_v->pt[0] * scale) + 0.5f;
coords[cnt + 1] = (ctx->latest_v->pt[1] * scale) + 0.5f;
Vertex *prev = ctx->latest_v->prev;
free(ctx->latest_v);
ctx->latest_v = prev;
}
(*env)->ReleasePrimitiveArrayCritical(env, obj_coords, coords, JNI_ABORT);
return cnt;
}
jint Java_org_oscim_renderer_sublayers_MeshLayer_tessGetIndices(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_indices) {
TessContext *ctx = CAST_CTX(ptr_context);
int length = (*env)->GetArrayLength(env, obj_indices);
jshort* tris = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_indices, 0);
if (tris == NULL) {
return 0;
}
int n_tris_copy = ctx->n_tris;
int cnt = 0;
for (; ctx->latest_t && cnt < length; cnt += 3) {
tris[cnt + 0] = ctx->latest_t->v[0];
tris[cnt + 1] = ctx->latest_t->v[1];
tris[cnt + 2] = ctx->latest_t->v[2];
Triangle *prev = ctx->latest_t->prev;
free(ctx->latest_t);
ctx->latest_t = prev;
n_tris_copy--;
}
ctx->n_tris = n_tris_copy;
(*env)->ReleasePrimitiveArrayCritical(env, obj_indices, tris, JNI_ABORT);
return cnt;
}
jlong Java_org_oscim_renderer_sublayers_MeshLayer_tessellate(JNIEnv *env, jclass c,
jfloatArray obj_points, jint pos,
jshortArray obj_index, jint ipos,
jint num_rings) { //, jintArray obj_out) {
jboolean isCopy;
printf("add %d %d %d\n", pos, ipos, num_rings);
float* orig_points = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_points, &isCopy);
if (orig_points == NULL)
return 0;
const float *points = orig_points + pos;
jshort* orig_indices = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_index, &isCopy);
if (orig_indices == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
return 0;
}
jshort* indices = orig_indices + ipos;
const float **rings = malloc(sizeof(float*) * (num_rings + 1));
int offset = 0;
for (int i = 0; i < num_rings; i++) {
rings[i] = points + offset;
offset += indices[i];
}
rings[num_rings] = points + offset;
int nverts, ntris;
TessContext *ctx = tessellate(&nverts, &ntris,
rings, rings + (num_rings + 1));
free(rings);
(*env)->ReleasePrimitiveArrayCritical(env, obj_index, orig_indices, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
return (long) ctx;
}

View File

@ -1,13 +0,0 @@
typedef struct Vertex {
double pt[3];
int index;
struct Vertex *prev;
} Vertex;
//void tessellate
// (double **verts,
// int *nverts,
// int **tris,
// int *ntris,
// const float **contoursbegin,
// const float **contoursend);

View File

@ -1,201 +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 "gluos.h"
#include <stdlib.h>
#include "geom.h"
#include "mesh.h"
#include "tessmono.h"
#include <assert.h>
#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
eDst->Sym->winding += eSrc->Sym->winding)
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
* (what else would it do??) The region must consist of a single
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
* case means that any vertical line intersects the interior of the
* region in a single interval.
*
* Tessellation consists of adding interior edges (actually pairs of
* half-edges), to split the region into non-overlapping triangles.
*
* The basic idea is explained in Preparata and Shamos (which I don''t
* have handy right now), although their implementation is more
* complicated than this one. The are two edge chains, an upper chain
* and a lower chain. We process all vertices from both chains in order,
* from right to left.
*
* The algorithm ensures that the following invariant holds after each
* vertex is processed: the untessellated region consists of two
* chains, where one chain (say the upper) is a single edge, and
* the other chain is concave. The left vertex of the single edge
* is always to the left of all vertices in the concave chain.
*
* Each step consists of adding the rightmost unprocessed vertex to one
* of the two chains, and forming a fan of triangles from the rightmost
* of two chain endpoints. Determining whether we can add each triangle
* to the fan is a simple orientation test. By making the fan as large
* as possible, we restore the invariant (check it yourself).
*/
int __gl_meshTessellateMonoRegion( GLUface *face )
{
GLUhalfEdge *up, *lo;
/* All edges are oriented CCW around the boundary of the region.
* First, find the half-edge whose origin vertex is rightmost.
* Since the sweep goes from left to right, face->anEdge should
* be close to the edge we want.
*/
up = face->anEdge;
assert( up->Lnext != up && up->Lnext->Lnext != up );
for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
;
for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
;
lo = up->Lprev;
while( up->Lnext != lo ) {
if( VertLeq( up->Dst, lo->Org )) {
/* up->Dst is on the left. It is safe to form triangles from lo->Org.
* The EdgeGoesLeft test guarantees progress even when some triangles
* are CW, given that the upper and lower chains are truly monotone.
*/
while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
|| EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
if (tempHalfEdge == NULL) return 0;
lo = tempHalfEdge->Sym;
}
lo = lo->Lprev;
} else {
/* lo->Org is on the left. We can make CCW triangles from up->Dst. */
while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
|| EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
if (tempHalfEdge == NULL) return 0;
up = tempHalfEdge->Sym;
}
up = up->Lnext;
}
}
/* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
* can be tessellated in a fan from this leftmost vertex.
*/
assert( lo->Lnext != up );
while( lo->Lnext->Lnext != up ) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
if (tempHalfEdge == NULL) return 0;
lo = tempHalfEdge->Sym;
}
return 1;
}
/* __gl_meshTessellateInterior( mesh ) tessellates each region of
* the mesh which is marked "inside" the polygon. Each such region
* must be monotone.
*/
int __gl_meshTessellateInterior( GLUmesh *mesh )
{
GLUface *f, *next;
/*LINTED*/
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
/* Make sure we don''t try to tessellate the new triangles. */
next = f->next;
if( f->inside ) {
if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
}
}
return 1;
}
/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
* which are not marked "inside" the polygon. Since further mesh operations
* on NULL faces are not allowed, the main purpose is to clean up the
* mesh so that exterior loops are not represented in the data structure.
*/
void __gl_meshDiscardExterior( GLUmesh *mesh )
{
GLUface *f, *next;
/*LINTED*/
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
/* Since f will be destroyed, save its next pointer. */
next = f->next;
if( ! f->inside ) {
__gl_meshZapFace( f );
}
}
}
#define MARKED_FOR_DELETION 0x7fffffff
/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
* winding numbers on all edges so that regions marked "inside" the
* polygon have a winding number of "value", and regions outside
* have a winding number of 0.
*
* If keepOnlyBoundary is TRUE, it also deletes all edges which do not
* separate an interior region from an exterior one.
*/
int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
GLboolean keepOnlyBoundary )
{
GLUhalfEdge *e, *eNext;
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
eNext = e->next;
if( e->Rface->inside != e->Lface->inside ) {
/* This is a boundary edge (one side is interior, one is exterior). */
e->winding = (e->Lface->inside) ? value : -value;
} else {
/* Both regions are interior, or both are exterior. */
if( ! keepOnlyBoundary ) {
e->winding = 0;
} else {
if ( !__gl_meshDelete( e ) ) return 0;
}
}
}
return 1;
}

View File

@ -1,71 +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

View File

@ -1,198 +0,0 @@
Triangle
A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
Version 1.6
Show Me
A Display Program for Meshes and More.
Version 1.6
Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk
2360 Woolsey #H
Berkeley, California 94705-1927
Please send bugs and comments to jrs@cs.berkeley.edu
Created as part of the Quake project (tools for earthquake simulation).
Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
There is no warranty whatsoever. Use at your own risk.
Triangle generates exact Delaunay triangulations, constrained Delaunay
triangulations, conforming Delaunay triangulations, Voronoi diagrams, and
high-quality triangular meshes. The latter can be generated with no small
or large angles, and are thus suitable for finite element analysis.
Show Me graphically displays the contents of the geometric files used by
Triangle. Show Me can also write images in PostScript form.
Information on the algorithms used by Triangle, including complete
references, can be found in the comments at the beginning of the triangle.c
source file. Another listing of these references, with PostScript copies
of some of the papers, is available from the Web page
http://www.cs.cmu.edu/~quake/triangle.research.html
------------------------------------------------------------------------------
These programs may be freely redistributed under the condition that the
copyright notices (including the copy of this notice in the code comments
and the copyright notice printed when the `-h' switch is selected) are
not removed, and no compensation is received. Private, research, and
institutional use is free. You may distribute modified versions of this
code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as
part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
WITH THE AUTHOR. (If you are not directly supplying this code to a
customer, and you are instead telling them how they can obtain it for
free, then you are not required to make any arrangement with me.)
------------------------------------------------------------------------------
The files included in this distribution are:
README The file you're reading now.
triangle.c Complete C source code for Triangle.
showme.c Complete C source code for Show Me.
triangle.h Include file for calling Triangle from another program.
tricall.c Sample program that calls Triangle.
makefile Makefile for compiling Triangle and Show Me.
A.poly A sample input file.
Each of Triangle and Show Me is a single portable C file. The easiest way
to compile them is to edit and use the included makefile. Before
compiling, read the makefile, which describes your options, and edit it
accordingly. You should specify:
The source and binary directories.
The C compiler and level of optimization.
The "correct" directories for include files (especially X include files),
if necessary.
Do you want single precision or double? (The default is double.) Do you
want to leave out some of Triangle's features to reduce the size of the
executable file? Investigate the SINGLE, REDUCED, and CDT_ONLY symbols.
If yours is not a Unix system, define the NO_TIMER symbol to remove the
Unix-specific timing code. Also, don't try to compile Show Me; it only
works with X Windows.
If you are compiling on an Intel x86 CPU and using gcc w/Linux or
Microsoft C, be sure to define the LINUX or CPU86 (for Microsoft) symbol
during compilation so that the exact arithmetic works right.
Once you've done this, type "make" to compile the programs. Alternatively,
the files are usually easy to compile without a makefile:
cc -O -o triangle triangle.c -lm
cc -O -o showme showme.c -lX11
On some systems, the C compiler won't be able to find the X include files
or libraries, and you'll need to specify an include path or library path:
cc -O -I/usr/local/include -o showme showme.c -L/usr/local/lib -lX11
Some processors, including Intel x86 family and possibly Motorola 68xxx
family chips, are IEEE conformant but have extended length internal
floating-point registers that may defeat Triangle's exact arithmetic
routines by failing to cause enough roundoff error! Typically, there is a
way to set these internal registers so that they are rounded off to IEEE
single or double precision format. I believe (but I'm not certain) that
Triangle has the right incantations for x86 chips, if you have gcc running
under Linux (define the LINUX compiler symbol) or Microsoft C (define the
CPU86 compiler symbol).
If you have a different processor or operating system, or if I got the
incantations wrong, you should check your C compiler or system manuals to
find out how to configure these internal registers to the precision you are
using. Otherwise, the exact arithmetic routines won't be exact at all.
See http://www.cs.cmu.edu/~quake/robust.pc.html for details. Triangle's
exact arithmetic hasn't a hope of working on machines like the Cray C90 or
Y-MP, which are not IEEE conformant and have inaccurate rounding.
Triangle and Show Me have both text and HTML documentation. The latter is
illustrated. Find it on the Web at
http://www.cs.cmu.edu/~quake/triangle.html
http://www.cs.cmu.edu/~quake/showme.html
Complete text instructions are printed by invoking each program with the
`-h' switch:
triangle -h
showme -h
The instructions are long; you'll probably want to pipe the output to
`more' or `lpr' or redirect it to a file.
Both programs give a short list of command line options if they are invoked
without arguments (that is, just type `triangle' or `showme').
Try out Triangle on the enclosed sample file, A.poly:
triangle -p A
showme A.poly &
Triangle will read the Planar Straight Line Graph defined by A.poly, and
write its constrained Delaunay triangulation to A.1.node and A.1.ele.
Show Me will display the figure defined by A.poly. There are two buttons
marked "ele" in the Show Me window; click on the top one. This will cause
Show Me to load and display the triangulation.
For contrast, try running
triangle -pq A
Now, click on the same "ele" button. A new triangulation will be loaded;
this one having no angles smaller than 20 degrees.
To see a Voronoi diagram, try this:
cp A.poly A.node
triangle -v A
Click the "ele" button again. You will see the Delaunay triangulation of
the points in A.poly, without the segments. Now click the top "voro" button.
You will see the Voronoi diagram corresponding to that Delaunay triangulation.
Click the "Reset" button to see the full extent of the diagram.
------------------------------------------------------------------------------
If you wish to call Triangle from another program, instructions for doing
so are contained in the file `triangle.h' (but read Triangle's regular
instructions first!). Also look at `tricall.c', which provides an example
of how to call Triangle.
Type "make trilibrary" to create triangle.o, a callable object file.
Alternatively, the object file is usually easy to compile without a
makefile:
cc -DTRILIBRARY -O -c triangle.c
Type "make distclean" to remove all the object and executable files created
by make.
------------------------------------------------------------------------------
If you use Triangle, and especially if you use it to accomplish real work,
I would like very much to hear from you. A short letter or email (to
jrs@cs.berkeley.edu) describing how you use Triangle will mean a lot to me.
The more people I know are using this program, the more easily I can
justify spending time on improvements and on the three-dimensional
successor to Triangle, which in turn will benefit you. Also, I can put you
on a list to receive email whenever a new version of Triangle is available.
If you use a mesh generated by Triangle or plotted by Show Me in a
publication, please include an acknowledgment as well. And please spell
Triangle with a capital `T'! If you want to include a citation, use
`Jonathan Richard Shewchuk, ``Triangle: Engineering a 2D Quality Mesh
Generator and Delaunay Triangulator,'' in Applied Computational Geometry:
Towards Geometric Engineering (Ming C. Lin and Dinesh Manocha, editors),
volume 1148 of Lecture Notes in Computer Science, pages 203-222,
Springer-Verlag, Berlin, May 1996. (From the First ACM Workshop on Applied
Computational Geometry.)'
Jonathan Richard Shewchuk
July 27, 2005

View File

@ -1,302 +0,0 @@
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "triangle.h"
#include <android/log.h>
#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Triangle", __VA_ARGS__)
// from www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
#if 0
int pnpoly(int nvert, float *vert, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = (nvert-1)*2; i < nvert * 2; j = i++)
{
if ( ((vert[i*2+1] > testy) != (vert[j*j+1] > testy)) &&
(testx < (vert[j*2]-vert[i*2])
* (testy - vert[i*2+1])
/ (vert[j*2+1]-vert[i*2+1]) + vert[i*2]) )
c = !c;
}
return c;
}
int compare_dups(const void *a, const void *b) {
int da = *((const long*) a);
int db = *((const long*) b);
return (da > db) - (da < db);
}
void shiftSegment(TriangleIO *in, int *seg, int pos) {
int size = (in->numberofsegments - pos - 1) * sizeof(int) * 2;
printf("shift %d - %d %d\n", size, in->numberofsegments, pos);
if (size > 0)
memmove(seg, seg + 2, size);
in->numberofsegments -= 1;
}
struct {
int p1;
int p2;
} segment;
#endif
static void printPoly(TriangleIO *in) {
// print poly format to check with triangle/showme
printf("%d 2 0 0\n", in->numberofpoints);
for (int j = 0; j < in->numberofpoints; j++)
printf("%d %f %f\n", j, in->pointlist[j*2], in->pointlist[j*2+1]);
int *seg = in->segmentlist;
printf("%d 0\n", in->numberofsegments);
for (int j = 0; j < in->numberofsegments; j++, seg += 2)
printf("%d %d %d\n", j, *seg, *(seg+1));
printf("%d 0\n", in->numberofholes);
for (int j = 0; j < in->numberofholes; j++) {
printf("%d %f %f\n", j, in->holelist[j*2], in->holelist[j*2+1]);
}
}
jint Java_org_oscim_renderer_sublayers_ExtrusionLayer_triangulate(JNIEnv *env, jclass c,
jfloatArray obj_points, jint pos, jint len, jint num_rings, jobject indice_buf, jint offset) {
jshort* indices = (jshort*) (*env)->GetDirectBufferAddress(env, indice_buf);
jboolean isCopy;
float* orig_points = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_points, &isCopy);
if (orig_points == NULL)
return 0;
float *points = orig_points + pos;
TriangleIO in, out;
char buf[128];
memset(&in, 0, sizeof(TriangleIO));
in.numberofpoints = len >> 1;
in.pointlist = (float *) points;
// check if explicitly closed
if (in.pointlist[0] == in.pointlist[indices[0] - 2]
&& in.pointlist[1] == in.pointlist[indices[0] - 1]) {
int point = 0;
for (int i = 0; i < num_rings; i++) {
// remove last point in ring
indices[i] -= 2;
int last = point + (indices[i] >> 1);
if (in.numberofpoints - last > 1)
memmove(in.pointlist + (last * 2), in.pointlist + ((last + 1) * 2),
(in.numberofpoints - last - 1) * 2 * sizeof(float));
in.numberofpoints--;
point = last;
}
}
int dups = 0;
float *i_points = points;
int *skip_list = NULL;
// check for duplicate vertices and keep a list
// of dups and the first occurence
for (int i = 0; i < in.numberofpoints - 1; i++) {
float x = *i_points++;
float y = *i_points++;
float *j_points = i_points;
for (int j = i + 1; j < in.numberofpoints; j++, j_points += 2) {
if ((*j_points == x) && (*(j_points + 1) == y)) {
skip_list = realloc(skip_list, (dups + 2) * 2 * sizeof(int));
skip_list[dups * 2 + 0] = j;
skip_list[dups * 2 + 1] = i;
dups++;
}
}
}
in.segmentlist = (int *) malloc(in.numberofpoints * 2 * sizeof(int));
in.numberofsegments = in.numberofpoints;
in.numberofholes = num_rings - 1;
int *rings = NULL;
if (in.numberofholes > 0) {
in.holelist = (float *) malloc(in.numberofholes * 2 * sizeof(float));
rings = (int*) malloc(num_rings * sizeof(int));
}
int *seg = in.segmentlist;
float *hole = in.holelist;
// counter going through all points
int point;
// counter going through all rings
int ring;
// assign all points to segments for each ring
for (ring = 0, point = 0; ring < num_rings; ring++, point++) {
int len;
int num_points = indices[ring] >> 1;
if (rings)
rings[ring] = num_points;
// add holes: we need a point inside the hole...
// this is just a heuristic, assuming that two
// 'parallel' lines have a distance of at least
// 1 unit. you'll notice when things went wrong
// when the hole is rendered instead of the poly
if (ring > 0) {
int k = point * 2;
float nx = in.pointlist[k++];
float ny = in.pointlist[k++];
float cx, cy, vx, vy;
// try to find a large enough segment
for (len = (point + num_points) * 2; k < len;) {
cx = nx;
cy = ny;
nx = in.pointlist[k++];
ny = in.pointlist[k++];
vx = nx - cx;
vy = ny - cy;
if (vx > 4 || vx < -4 || vy > 4 || vy < -4)
break;
}
float a = sqrt(vx * vx + vy * vy);
float ux = -vy / a;
float uy = vx / a;
float centerx = cx + vx / 2.0 - (ux * 0.1);
float centery = cy + vy / 2.0 - (uy * 0.1);
*hole++ = centerx;
*hole++ = centery;
}
// close ring
int last = point + (num_points - 1);
*seg++ = last;
*seg++ = point;
for (len = point + num_points - 1; point < len; point++) {
*seg++ = point;
*seg++ = point + 1;
}
}
if (dups) {
for (int i = 0; i < dups; i++) {
printf("duplicate points at %d, %d: %f,%f\n",
skip_list[i*2], skip_list[i*2+1],
in.pointlist[skip_list[i*2+1]*2],
in.pointlist[skip_list[i*2+1]*2+1]);
}
printPoly(&in);
// replace duplicate positions with first occurence
for (int i = 0; i < dups; i++) {
// position of the duplicate vertex
int pos = skip_list[i * 2] - i;
// first vertex
int replacement = skip_list[i * 2 + 1];
seg = in.segmentlist;
for (int j = 0; j < in.numberofsegments * 2; j++, seg++) {
if (*seg == pos) {
printf("%d: %d <- %d", j, pos, replacement);
*seg = replacement;
}
}
}
}
memset(&out, 0, sizeof(TriangleIO));
out.trianglelist = (INDICE*) indices;
// p - use polygon input, for CDT
// z - zero offset array offsets...
// P - no poly output
// N - no node output
// B - no bound output
// Q - be quiet!
TriangleOptions opt;
memset(&opt, 0, sizeof(TriangleOptions));
opt.dwyer = 1;
opt.steiner = -1;
opt.order = 1;
opt.maxarea = -1.0;
opt.poly = 1;
opt.usesegments = 1;
opt.nopolywritten = 1;
opt.nonodewritten = 1;
opt.nobound = 1;
opt.quiet = 1;
triangulate(&opt, &in, &out, (TriangleIO *) NULL);
if (in.numberofpoints < out.numberofpoints) {
// TODO rerun with 'nonodewritten = 0'
printf( "polygon input is bad! points in:%d out%d\n", in.numberofpoints, out.numberofpoints);
out.numberoftriangles = 0;
}
else {
// scale to stride and add offset
short stride = 2;
if (offset < 0)
offset = 0;
INDICE *tri = out.trianglelist;
for (int n = out.numberoftriangles * 3; n > 0; n--)
*tri++ = *tri * stride + offset;
// when a ring has an odd number of points one (or rather two)
// additional vertices will be added. so the following rings
// needs extra offset...
int start = offset;
for (int j = 0, m = in.numberofholes; j < m; j++) {
start += rings[j] * stride;
// even number of points?
if (!(rings[j] & 1))
continue;
tri = out.trianglelist;
int n = out.numberoftriangles * 3;
for (; n-- > 0; tri++)
if (*tri >= start)
*tri += stride;
start += stride;
}
}
(*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
free(in.segmentlist);
free(in.holelist);
free(rings);
free(skip_list);
return out.numberoftriangles;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,360 +0,0 @@
/*****************************************************************************/
/* */
/* (triangle.h) */
/* */
/* Include file for programs that call Triangle. */
/* */
/* Accompanies Triangle Version 1.6 */
/* July 28, 2005 */
/* */
/* Copyright 1996, 2005 */
/* Jonathan Richard Shewchuk */
/* 2360 Woolsey #H */
/* Berkeley, California 94705-1927 */
/* jrs@cs.berkeley.edu */
/* */
/*****************************************************************************/
/*****************************************************************************/
/* */
/* How to call Triangle from another program */
/* */
/* */
/* If you haven't read Triangle's instructions (run "triangle -h" to read */
/* them), you won't understand what follows. */
/* */
/* Triangle must be compiled into an object file (triangle.o) with the */
/* TRILIBRARY symbol defined (generally by using the -DTRILIBRARY compiler */
/* switch). The makefile included with Triangle will do this for you if */
/* you run "make trilibrary". The resulting object file can be called via */
/* the procedure triangulate(). */
/* */
/* If the size of the object file is important to you, you may wish to */
/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */
/* of all features that are primarily of research interest. Specifically, */
/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */
/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */
/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */
/* eliminates Triangle's -r, -q, -a, -u, -D, -Y, -S, and -s switches. */
/* */
/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */
/* made in the makefile or in triangle.c itself. Putting these definitions */
/* in this file (triangle.h) will not create the desired effect. */
/* */
/* */
/* The calling convention for triangulate() follows. */
/* */
/* void triangulate(triswitches, in, out, vorout) */
/* char *triswitches; */
/* struct triangulateio *in; */
/* struct triangulateio *out; */
/* struct triangulateio *vorout; */
/* */
/* `triswitches' is a string containing the command line switches you wish */
/* to invoke. No initial dash is required. Some suggestions: */
/* */
/* - You'll probably find it convenient to use the `z' switch so that */
/* points (and other items) are numbered from zero. This simplifies */
/* indexing, because the first item of any type always starts at index */
/* [0] of the corresponding array, whether that item's number is zero or */
/* one. */
/* - You'll probably want to use the `Q' (quiet) switch in your final code, */
/* but you can take advantage of Triangle's printed output (including the */
/* `V' switch) while debugging. */
/* - If you are not using the `q', `a', `u', `D', `j', or `s' switches, */
/* then the output points will be identical to the input points, except */
/* possibly for the boundary markers. If you don't need the boundary */
/* markers, you should use the `N' (no nodes output) switch to save */
/* memory. (If you do need boundary markers, but need to save memory, a */
/* good nasty trick is to set out->pointlist equal to in->pointlist */
/* before calling triangulate(), so that Triangle overwrites the input */
/* points with identical copies.) */
/* - The `I' (no iteration numbers) and `g' (.off file output) switches */
/* have no effect when Triangle is compiled with TRILIBRARY defined. */
/* */
/* `in', `out', and `vorout' are descriptions of the input, the output, */
/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */
/* `vorout' may be NULL. `in' and `out' may never be NULL. */
/* */
/* Certain fields of the input and output structures must be initialized, */
/* as described below. */
/* */
/*****************************************************************************/
/*****************************************************************************/
/* */
/* The `triangulateio' structure. */
/* */
/* Used to pass data into and out of the triangulate() procedure. */
/* */
/* */
/* Arrays are used to store points, triangles, markers, and so forth. In */
/* all cases, the first item in any array is stored starting at index [0]. */
/* However, that item is item number `1' unless the `z' switch is used, in */
/* which case it is item number `0'. Hence, you may find it easier to */
/* index points (and triangles in the neighbor list) if you use the `z' */
/* switch. Unless, of course, you're calling Triangle from a Fortran */
/* program. */
/* */
/* Description of fields (except the `numberof' fields, which are obvious): */
/* */
/* `pointlist': An array of point coordinates. The first point's x */
/* coordinate is at index [0] and its y coordinate at index [1], followed */
/* by the coordinates of the remaining points. Each point occupies two */
/* REALs. */
/* `pointattributelist': An array of point attributes. Each point's */
/* attributes occupy `numberofpointattributes' REALs. */
/* `pointmarkerlist': An array of point markers; one int per point. */
/* */
/* `trianglelist': An array of triangle corners. The first triangle's */
/* first corner is at index [0], followed by its other two corners in */
/* counterclockwise order, followed by any other nodes if the triangle */
/* represents a nonlinear element. Each triangle occupies */
/* `numberofcorners' ints. */
/* `triangleattributelist': An array of triangle attributes. Each */
/* triangle's attributes occupy `numberoftriangleattributes' REALs. */
/* `trianglearealist': An array of triangle area constraints; one REAL per */
/* triangle. Input only. */
/* `neighborlist': An array of triangle neighbors; three ints per */
/* triangle. Output only. */
/* */
/* `segmentlist': An array of segment endpoints. The first segment's */
/* endpoints are at indices [0] and [1], followed by the remaining */
/* segments. Two ints per segment. */
/* `segmentmarkerlist': An array of segment markers; one int per segment. */
/* */
/* `holelist': An array of holes. The first hole's x and y coordinates */
/* are at indices [0] and [1], followed by the remaining holes. Two */
/* REALs per hole. Input only, although the pointer is copied to the */
/* output structure for your convenience. */
/* */
/* `regionlist': An array of regional attributes and area constraints. */
/* The first constraint's x and y coordinates are at indices [0] and [1], */
/* followed by the regional attribute at index [2], followed by the */
/* maximum area at index [3], followed by the remaining area constraints. */
/* Four REALs per area constraint. Note that each regional attribute is */
/* used only if you select the `A' switch, and each area constraint is */
/* used only if you select the `a' switch (with no number following), but */
/* omitting one of these switches does not change the memory layout. */
/* Input only, although the pointer is copied to the output structure for */
/* your convenience. */
/* */
/* `edgelist': An array of edge endpoints. The first edge's endpoints are */
/* at indices [0] and [1], followed by the remaining edges. Two ints per */
/* edge. Output only. */
/* `edgemarkerlist': An array of edge markers; one int per edge. Output */
/* only. */
/* `normlist': An array of normal vectors, used for infinite rays in */
/* Voronoi diagrams. The first normal vector's x and y magnitudes are */
/* at indices [0] and [1], followed by the remaining vectors. For each */
/* finite edge in a Voronoi diagram, the normal vector written is the */
/* zero vector. Two REALs per edge. Output only. */
/* */
/* */
/* Any input fields that Triangle will examine must be initialized. */
/* Furthermore, for each output array that Triangle will write to, you */
/* must either provide space by setting the appropriate pointer to point */
/* to the space you want the data written to, or you must initialize the */
/* pointer to NULL, which tells Triangle to allocate space for the results. */
/* The latter option is preferable, because Triangle always knows exactly */
/* how much space to allocate. The former option is provided mainly for */
/* people who need to call Triangle from Fortran code, though it also makes */
/* possible some nasty space-saving tricks, like writing the output to the */
/* same arrays as the input. */
/* */
/* Triangle will not free() any input or output arrays, including those it */
/* allocates itself; that's up to you. You should free arrays allocated by */
/* Triangle by calling the trifree() procedure defined below. (By default, */
/* trifree() just calls the standard free() library procedure, but */
/* applications that call triangulate() may replace trimalloc() and */
/* trifree() in triangle.c to use specialized memory allocators.) */
/* */
/* Here's a guide to help you decide which fields you must initialize */
/* before you call triangulate(). */
/* */
/* `in': */
/* */
/* - `pointlist' must always point to a list of points; `numberofpoints' */
/* and `numberofpointattributes' must be properly set. */
/* `pointmarkerlist' must either be set to NULL (in which case all */
/* markers default to zero), or must point to a list of markers. If */
/* `numberofpointattributes' is not zero, `pointattributelist' must */
/* point to a list of point attributes. */
/* - If the `r' switch is used, `trianglelist' must point to a list of */
/* triangles, and `numberoftriangles', `numberofcorners', and */
/* `numberoftriangleattributes' must be properly set. If */
/* `numberoftriangleattributes' is not zero, `triangleattributelist' */
/* must point to a list of triangle attributes. If the `a' switch is */
/* used (with no number following), `trianglearealist' must point to a */
/* list of triangle area constraints. `neighborlist' may be ignored. */
/* - If the `p' switch is used, `segmentlist' must point to a list of */
/* segments, `numberofsegments' must be properly set, and */
/* `segmentmarkerlist' must either be set to NULL (in which case all */
/* markers default to zero), or must point to a list of markers. */
/* - If the `p' switch is used without the `r' switch, then */
/* `numberofholes' and `numberofregions' must be properly set. If */
/* `numberofholes' is not zero, `holelist' must point to a list of */
/* holes. If `numberofregions' is not zero, `regionlist' must point to */
/* a list of region constraints. */
/* - If the `p' switch is used, `holelist', `numberofholes', */
/* `regionlist', and `numberofregions' is copied to `out'. (You can */
/* nonetheless get away with not initializing them if the `r' switch is */
/* used.) */
/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
/* ignored. */
/* */
/* `out': */
/* */
/* - `pointlist' must be initialized (NULL or pointing to memory) unless */
/* the `N' switch is used. `pointmarkerlist' must be initialized */
/* unless the `N' or `B' switch is used. If `N' is not used and */
/* `in->numberofpointattributes' is not zero, `pointattributelist' must */
/* be initialized. */
/* - `trianglelist' must be initialized unless the `E' switch is used. */
/* `neighborlist' must be initialized if the `n' switch is used. If */
/* the `E' switch is not used and (`in->numberofelementattributes' is */
/* not zero or the `A' switch is used), `elementattributelist' must be */
/* initialized. `trianglearealist' may be ignored. */
/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */
/* and the `P' switch is not used. `segmentmarkerlist' must also be */
/* initialized under these circumstances unless the `B' switch is used. */
/* - `edgelist' must be initialized if the `e' switch is used. */
/* `edgemarkerlist' must be initialized if the `e' switch is used and */
/* the `B' switch is not. */
/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
/* */
/* `vorout' (only needed if `v' switch is used): */
/* */
/* - `pointlist' must be initialized. If `in->numberofpointattributes' */
/* is not zero, `pointattributelist' must be initialized. */
/* `pointmarkerlist' may be ignored. */
/* - `edgelist' and `normlist' must both be initialized. */
/* `edgemarkerlist' may be ignored. */
/* - Everything else may be ignored. */
/* */
/* After a call to triangulate(), the valid fields of `out' and `vorout' */
/* will depend, in an obvious way, on the choice of switches used. Note */
/* that when the `p' switch is used, the pointers `holelist' and */
/* `regionlist' are copied from `in' to `out', but no new space is */
/* allocated; be careful that you don't free() the same array twice. On */
/* the other hand, Triangle will never copy the `pointlist' pointer (or any */
/* others); new space is allocated for `out->pointlist', or if the `N' */
/* switch is used, `out->pointlist' remains uninitialized. */
/* */
/* All of the meaningful `numberof' fields will be properly set; for */
/* instance, `numberofedges' will represent the number of edges in the */
/* triangulation whether or not the edges were written. If segments are */
/* not used, `numberofsegments' will indicate the number of boundary edges. */
/* */
/*****************************************************************************/
#define SINGLE
#ifdef SINGLE
#define REAL float
#else /* not SINGLE */
#define REAL double
#endif /* not SINGLE */
#define INDICE unsigned short
typedef struct triangulateio TriangleIO;
struct triangulateio {
REAL *pointlist; /* In / out */
REAL *pointattributelist; /* In / out */
int *pointmarkerlist; /* In / out */
int numberofpoints; /* In / out */
int numberofpointattributes; /* In / out */
INDICE *trianglelist; /* In / out */
REAL *triangleattributelist; /* In / out */
REAL *trianglearealist; /* In only */
int *neighborlist; /* Out only */
int numberoftriangles; /* In / out */
int numberofcorners; /* In / out */
int numberoftriangleattributes; /* In / out */
int *segmentlist; /* In / out */
int *segmentmarkerlist; /* In / out */
int numberofsegments; /* In / out */
REAL *holelist; /* In / pointer to array copied out */
int numberofholes; /* In / copied out */
REAL *regionlist; /* In / pointer to array copied out */
int numberofregions; /* In / copied out */
int *edgelist; /* Out only */
int *edgemarkerlist; /* Not used with Voronoi diagram; out only */
REAL *normlist; /* Used only with Voronoi diagram; out only */
int numberofedges; /* Out only */
};
/* Data structure for command line switches and file names. This structure
/* is used (instead of global variables) to allow reentrancy.
* Switches for the triangulator.
* poly: -p switch.
* refine: -r switch.
* quality: -q switch.
* minangle: minimum angle bound, specified after -q switch.
* goodangle: cosine squared of minangle.
* offconstant: constant used to place off-center Steiner points.
* vararea: -a switch without number.
* fixedarea: -a switch with number.
* maxarea: maximum area bound, specified after -a switch.
* usertest: -u switch.
* regionattrib: -A switch.
* convex: -c switch.
* weighted: 1 for -w switch, 2 for -W switch.
* jettison: -j switch
* firstnumber: inverse of -z switch. All items are numbered starting
* from `firstnumber'.
* edgesout: -e switch.
* voronoi: -v switch.
* neighbors: -n switch.
* geomview: -g switch.
* nobound: -B switch.
* nopolywritten: -P switch.
* nonodewritten: -N switch.
* noelewritten: -E switch.
* noiterationnum: -I switch.
* noholes: -O switch.
* noexact: -X switch.
* order: element order, specified after -o switch.
* nobisect: count of how often -Y switch is selected.
* steiner: maximum number of Steiner points, specified after -S switch.
* incremental: -i switch. sweepline: -F switch.
* dwyer: inverse of -l switch.
* splitseg: -s switch.
* conformdel: -D switch. docheck: -C switch.
* quiet: -Q switch. verbose: count of how often -V switch is selected.
* usesegments: -p, -r, -q, or -c switch; determines whether segments are
* used at all.
*
* Read the instructions to find out the meaning of these switches. */
typedef struct behavior TriangleOptions;
struct behavior {
int poly, refine, quality, vararea, fixedarea, usertest;
int regionattrib, convex, weighted, jettison;
int firstnumber;
int edgesout, voronoi, neighbors, geomview;
int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum;
int noholes, noexact, conformdel;
int incremental, sweepline, dwyer;
int splitseg;
int docheck;
int quiet, verbose;
int usesegments;
int order;
int nobisect;
int steiner;REAL minangle, goodangle, offconstant;REAL maxarea;
};
void parsecommandline(int argc, char **argv, struct behavior *b);
void triangulate(struct behavior *, struct triangulateio *, struct triangulateio *,
struct triangulateio *);

View File

@ -1,441 +0,0 @@
#include "triangle_private.h"
/*****************************************************************************/
/* */
/* quality_statistics() Print statistics about the quality of the mesh. */
/* */
/*****************************************************************************/
void quality_statistics(struct mesh *m, struct behavior *b) {
struct otri triangleloop;
vertex p[3];
REAL cossquaretable[8];
REAL ratiotable[16];
REAL dx[3], dy[3];
REAL edgelength[3];
REAL dotproduct;
REAL cossquare;
REAL triarea;
REAL shortest, longest;
REAL trilongest2;
REAL smallestarea, biggestarea;
REAL triminaltitude2;
REAL minaltitude;
REAL triaspect2;
REAL worstaspect;
REAL smallestangle, biggestangle;
REAL radconst, degconst;
int angletable[18];
int aspecttable[16];
int aspectindex;
int tendegree;
int acutebiggest;
int i, ii, j, k;
printf("Mesh quality statistics:\n\n");
radconst = PI / 18.0;
degconst = 180.0 / PI;
for (i = 0; i < 8; i++) {
cossquaretable[i] = cos(radconst * (REAL) (i + 1));
cossquaretable[i] = cossquaretable[i] * cossquaretable[i];
}
for (i = 0; i < 18; i++) {
angletable[i] = 0;
}
ratiotable[0] = 1.5;
ratiotable[1] = 2.0;
ratiotable[2] = 2.5;
ratiotable[3] = 3.0;
ratiotable[4] = 4.0;
ratiotable[5] = 6.0;
ratiotable[6] = 10.0;
ratiotable[7] = 15.0;
ratiotable[8] = 25.0;
ratiotable[9] = 50.0;
ratiotable[10] = 100.0;
ratiotable[11] = 300.0;
ratiotable[12] = 1000.0;
ratiotable[13] = 10000.0;
ratiotable[14] = 100000.0;
ratiotable[15] = 0.0;
for (i = 0; i < 16; i++) {
aspecttable[i] = 0;
}
worstaspect = 0.0;
minaltitude = m->xmax - m->xmin + m->ymax - m->ymin;
minaltitude = minaltitude * minaltitude;
shortest = minaltitude;
longest = 0.0;
smallestarea = minaltitude;
biggestarea = 0.0;
worstaspect = 0.0;
smallestangle = 0.0;
biggestangle = 2.0;
acutebiggest = 1;
traversalinit(&m->triangles);
triangleloop.tri = triangletraverse(m);
triangleloop.orient = 0;
while (triangleloop.tri != (triangle *) NULL) {
org(triangleloop, p[0]);
dest(triangleloop, p[1]);
apex(triangleloop, p[2]);
trilongest2 = 0.0;
for (i = 0; i < 3; i++) {
j = plus1mod3[i];
k = minus1mod3[i];
dx[i] = p[j][0] - p[k][0];
dy[i] = p[j][1] - p[k][1];
edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
if (edgelength[i] > trilongest2) {
trilongest2 = edgelength[i];
}
if (edgelength[i] > longest) {
longest = edgelength[i];
}
if (edgelength[i] < shortest) {
shortest = edgelength[i];
}
}
triarea = counterclockwise(m, b, p[0], p[1], p[2]);
if (triarea < smallestarea) {
smallestarea = triarea;
}
if (triarea > biggestarea) {
biggestarea = triarea;
}
triminaltitude2 = triarea * triarea / trilongest2;
if (triminaltitude2 < minaltitude) {
minaltitude = triminaltitude2;
}
triaspect2 = trilongest2 / triminaltitude2;
if (triaspect2 > worstaspect) {
worstaspect = triaspect2;
}
aspectindex = 0;
while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) && (aspectindex < 15)) {
aspectindex++;
}
aspecttable[aspectindex]++;
for (i = 0; i < 3; i++) {
j = plus1mod3[i];
k = minus1mod3[i];
dotproduct = dx[j] * dx[k] + dy[j] * dy[k];
cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]);
tendegree = 8;
for (ii = 7; ii >= 0; ii--) {
if (cossquare > cossquaretable[ii]) {
tendegree = ii;
}
}
if (dotproduct <= 0.0) {
angletable[tendegree]++;
if (cossquare > smallestangle) {
smallestangle = cossquare;
}
if (acutebiggest && (cossquare < biggestangle)) {
biggestangle = cossquare;
}
}
else {
angletable[17 - tendegree]++;
if (acutebiggest || (cossquare > biggestangle)) {
biggestangle = cossquare;
acutebiggest = 0;
}
}
}
triangleloop.tri = triangletraverse(m);
}
shortest = sqrt(shortest);
longest = sqrt(longest);
minaltitude = sqrt(minaltitude);
worstaspect = sqrt(worstaspect);
smallestarea *= 0.5;
biggestarea *= 0.5;
if (smallestangle >= 1.0) {
smallestangle = 0.0;
}
else {
smallestangle = degconst * acos(sqrt(smallestangle));
}
if (biggestangle >= 1.0) {
biggestangle = 180.0;
}
else {
if (acutebiggest) {
biggestangle = degconst * acos(sqrt(biggestangle));
}
else {
biggestangle = 180.0 - degconst * acos(sqrt(biggestangle));
}
}
printf(" Smallest area: %16.5g | Largest area: %16.5g\n", smallestarea, biggestarea);
printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", shortest, longest);
printf(
" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", minaltitude, worstaspect);
printf(" Triangle aspect ratio histogram:\n");
printf(
" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], aspecttable[8]);
for (i = 1; i < 7; i++) {
printf(
" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[i - 1], ratiotable[i], aspecttable[i], ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]);
}
printf(
" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], aspecttable[15]);
printf(" (Aspect ratio is longest edge divided by shortest altitude)\n\n");
printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", smallestangle, biggestangle);
printf(" Angle histogram:\n");
for (i = 0; i < 9; i++) {
printf(
" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", i * 10, i * 10 + 10, angletable[i], i * 10 + 90, i * 10 + 100, angletable[i + 9]);
}
printf("\n");
}
/*****************************************************************************/
/* */
/* statistics() Print all sorts of cool facts. */
/* */
/*****************************************************************************/
void statistics(struct mesh *m, struct behavior *b) {
printf("\nStatistics:\n\n");
printf(" Input vertices: %d\n", m->invertices);
if (b->refine) {
printf(" Input triangles: %d\n", m->inelements);
}
if (b->poly) {
printf(" Input segments: %d\n", m->insegments);
if (!b->refine) {
printf(" Input holes: %d\n", m->holes);
}
}
printf("\n Mesh vertices: %ld\n", m->vertices.items - m->undeads);
printf(" Mesh triangles: %ld\n", m->triangles.items);
printf(" Mesh edges: %ld\n", m->edges);
printf(" Mesh exterior boundary edges: %ld\n", m->hullsize);
if (b->poly || b->refine) {
printf(" Mesh interior boundary edges: %ld\n", m->subsegs.items - m->hullsize);
printf(" Mesh subsegments (constrained edges): %ld\n", m->subsegs.items);
}
printf("\n");
if (b->verbose) {
quality_statistics(m, b);
printf("Memory allocation statistics:\n\n");
printf(" Maximum number of vertices: %ld\n", m->vertices.maxitems);
printf(" Maximum number of triangles: %ld\n", m->triangles.maxitems);
if (m->subsegs.maxitems > 0) {
printf(" Maximum number of subsegments: %ld\n", m->subsegs.maxitems);
}
if (m->viri.maxitems > 0) {
printf(" Maximum number of viri: %ld\n", m->viri.maxitems);
}
if (m->badsubsegs.maxitems > 0) {
printf(" Maximum number of encroached subsegments: %ld\n", m->badsubsegs.maxitems);
}
if (m->badtriangles.maxitems > 0) {
printf(" Maximum number of bad triangles: %ld\n", m->badtriangles.maxitems);
}
if (m->flipstackers.maxitems > 0) {
printf(" Maximum number of stacked triangle flips: %ld\n", m->flipstackers.maxitems);
}
if (m->splaynodes.maxitems > 0) {
printf(" Maximum number of splay tree nodes: %ld\n", m->splaynodes.maxitems);
}
printf(
" Approximate heap memory use (bytes): %ld\n\n", m->vertices.maxitems * m->vertices.itembytes + m->triangles.maxitems * m->triangles.itembytes + m->subsegs.maxitems * m->subsegs.itembytes + m->viri.maxitems * m->viri.itembytes + m->badsubsegs.maxitems * m->badsubsegs.itembytes + m->badtriangles.maxitems * m->badtriangles.itembytes + m->flipstackers.maxitems * m->flipstackers.itembytes + m->splaynodes.maxitems * m->splaynodes.itembytes);
printf("Algorithmic statistics:\n\n");
if (!b->weighted) {
printf(" Number of incircle tests: %ld\n", m->incirclecount);
}
else {
printf(" Number of 3D orientation tests: %ld\n", m->orient3dcount);
}
printf(" Number of 2D orientation tests: %ld\n", m->counterclockcount);
if (m->hyperbolacount > 0) {
printf(" Number of right-of-hyperbola tests: %ld\n", m->hyperbolacount);
}
if (m->circletopcount > 0) {
printf(" Number of circle top computations: %ld\n", m->circletopcount);
}
if (m->circumcentercount > 0) {
printf(" Number of triangle circumcenter computations: %ld\n", m->circumcentercount);
}
printf("\n");
}
}
/********* Debugging routines begin here *********/
/** **/
/** **/
/*****************************************************************************/
/* */
/* printtriangle() Print out the details of an oriented triangle. */
/* */
/* I originally wrote this procedure to simplify debugging; it can be */
/* called directly from the debugger, and presents information about an */
/* oriented triangle in digestible form. It's also used when the */
/* highest level of verbosity (`-VVV') is specified. */
/* */
/*****************************************************************************/
void printtriangle(struct mesh *m, struct behavior *b, struct otri *t) {
struct otri printtri;
struct osub printsh;
vertex printvertex;
printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, t->orient);
decode(t->tri[0], printtri);
if (printtri.tri == m->dummytri) {
printf(" [0] = Outer space\n");
}
else {
printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
}
decode(t->tri[1], printtri);
if (printtri.tri == m->dummytri) {
printf(" [1] = Outer space\n");
}
else {
printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
}
decode(t->tri[2], printtri);
if (printtri.tri == m->dummytri) {
printf(" [2] = Outer space\n");
}
else {
printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
}
org(*t, printvertex);
if (printvertex == (vertex) NULL)
printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
else
printf(
" Origin[%d] = x%lx (%.12g, %.12g)\n", (t->orient + 1) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
dest(*t, printvertex);
if (printvertex == (vertex) NULL)
printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3);
else
printf(
" Dest [%d] = x%lx (%.12g, %.12g)\n", (t->orient + 2) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
apex(*t, printvertex);
if (printvertex == (vertex) NULL)
printf(" Apex [%d] = NULL\n", t->orient + 3);
else
printf(
" Apex [%d] = x%lx (%.12g, %.12g)\n", t->orient + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
if (b->usesegments) {
sdecode(t->tri[6], printsh);
if (printsh.ss != m->dummysub) {
printf(" [6] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
}
sdecode(t->tri[7], printsh);
if (printsh.ss != m->dummysub) {
printf(" [7] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
}
sdecode(t->tri[8], printsh);
if (printsh.ss != m->dummysub) {
printf(" [8] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
}
}
if (b->vararea) {
printf(" Area constraint: %.4g\n", areabound(*t));
}
}
/*****************************************************************************/
/* */
/* printsubseg() Print out the details of an oriented subsegment. */
/* */
/* I originally wrote this procedure to simplify debugging; it can be */
/* called directly from the debugger, and presents information about an */
/* oriented subsegment in digestible form. It's also used when the highest */
/* level of verbosity (`-VVV') is specified. */
/* */
/*****************************************************************************/
void printsubseg(struct mesh *m, struct behavior *b, struct osub *s) {
struct osub printsh;
struct otri printtri;
vertex printvertex;
printf(
"subsegment x%lx with orientation %d and mark %d:\n", (unsigned long) s->ss, s->ssorient, mark(*s));
sdecode(s->ss[0], printsh);
if (printsh.ss == m->dummysub) {
printf(" [0] = No subsegment\n");
}
else {
printf(" [0] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
}
sdecode(s->ss[1], printsh);
if (printsh.ss == m->dummysub) {
printf(" [1] = No subsegment\n");
}
else {
printf(" [1] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
}
sorg(*s, printvertex);
if (printvertex == (vertex) NULL)
printf(" Origin[%d] = NULL\n", 2 + s->ssorient);
else
printf(
" Origin[%d] = x%lx (%.12g, %.12g)\n", 2 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
sdest(*s, printvertex);
if (printvertex == (vertex) NULL)
printf(" Dest [%d] = NULL\n", 3 - s->ssorient);
else
printf(
" Dest [%d] = x%lx (%.12g, %.12g)\n", 3 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
decode(s->ss[6], printtri);
if (printtri.tri == m->dummytri) {
printf(" [6] = Outer space\n");
}
else {
printf(" [6] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
}
decode(s->ss[7], printtri);
if (printtri.tri == m->dummytri) {
printf(" [7] = Outer space\n");
}
else {
printf(" [7] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
}
segorg(*s, printvertex);
if (printvertex == (vertex) NULL)
printf(" Segment origin[%d] = NULL\n", 4 + s->ssorient);
else
printf(
" Segment origin[%d] = x%lx (%.12g, %.12g)\n", 4 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
segdest(*s, printvertex);
if (printvertex == (vertex) NULL)
printf(" Segment dest [%d] = NULL\n", 5 - s->ssorient);
else
printf(
" Segment dest [%d] = x%lx (%.12g, %.12g)\n", 5 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
}
/** **/
/** **/
/********* Debugging routines end here *********/

File diff suppressed because it is too large Load Diff