Add triangle to quad conversion, not finish yet.
Fix convex hull algorithm. Unify generated faces'normal. Add hashtable. Fix incorrect realloc in array.master
parent
97141d9ee7
commit
e9e9a170e3
|
@ -15,7 +15,9 @@ SOURCES += main.cpp \
|
||||||
array.c \
|
array.c \
|
||||||
bmesh.c \
|
bmesh.c \
|
||||||
matrix.c \
|
matrix.c \
|
||||||
convexhull.c
|
convexhull.c \
|
||||||
|
tri2quad.c \
|
||||||
|
hashtable.c
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
render.h \
|
render.h \
|
||||||
|
@ -24,4 +26,6 @@ HEADERS += mainwindow.h \
|
||||||
array.h \
|
array.h \
|
||||||
bmesh.h \
|
bmesh.h \
|
||||||
matrix.h \
|
matrix.h \
|
||||||
convexhull.h
|
convexhull.h \
|
||||||
|
tri2quad.h \
|
||||||
|
hashtable.h
|
|
@ -23,11 +23,16 @@ array *arrayCreate(int nodeSize) {
|
||||||
int arraySetLength(array *arr, int length) {
|
int arraySetLength(array *arr, int length) {
|
||||||
if (length > arr->capacity) {
|
if (length > arr->capacity) {
|
||||||
int newCapacity = (arr->capacity + 1) * 2;
|
int newCapacity = (arr->capacity + 1) * 2;
|
||||||
|
if (newCapacity < length) {
|
||||||
|
newCapacity = length;
|
||||||
|
}
|
||||||
char *newNodes = (char *)realloc(arr->nodes, arr->nodeSize * newCapacity);
|
char *newNodes = (char *)realloc(arr->nodes, arr->nodeSize * newCapacity);
|
||||||
if (!newNodes) {
|
if (!newNodes) {
|
||||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
memset(newNodes + arr->nodeSize * arr->capacity, 0,
|
||||||
|
arr->nodeSize * (newCapacity - arr->capacity));
|
||||||
arr->capacity = newCapacity;
|
arr->capacity = newCapacity;
|
||||||
arr->nodes = newNodes;
|
arr->nodes = newNodes;
|
||||||
}
|
}
|
||||||
|
|
130
src/bmesh.c
130
src/bmesh.c
|
@ -3,10 +3,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
#include "bmesh.h"
|
#include "bmesh.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "convexhull.h"
|
#include "convexhull.h"
|
||||||
|
#include "tri2quad.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
#define BMESH_STEP_DISTANCE 0.4
|
#define BMESH_STEP_DISTANCE 0.4
|
||||||
|
@ -518,9 +520,12 @@ static bmeshBall *bmeshFindBallForConvexHull(bmesh *bm, bmeshBall *root,
|
||||||
return bmeshFindBallForConvexHull(bm, root, child);
|
return bmeshFindBallForConvexHull(bm, root, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addBallToHull(convexHull *hull, bmeshBall *ballForConvexHull) {
|
static void addBallToHull(convexHull *hull, bmeshBall *ballForConvexHull,
|
||||||
|
bmeshBall **outmostBall, int *outmostBallFirstVertexIndex) {
|
||||||
vec3 z, y;
|
vec3 z, y;
|
||||||
quad q;
|
quad q;
|
||||||
|
int vertexIndex[4];
|
||||||
|
int needUpdateOutmost = 0;
|
||||||
|
|
||||||
vec3Scale(&ballForConvexHull->localYaxis, ballForConvexHull->radius, &y);
|
vec3Scale(&ballForConvexHull->localYaxis, ballForConvexHull->radius, &y);
|
||||||
vec3Scale(&ballForConvexHull->localZaxis, ballForConvexHull->radius, &z);
|
vec3Scale(&ballForConvexHull->localZaxis, ballForConvexHull->radius, &z);
|
||||||
|
@ -533,10 +538,22 @@ static void addBallToHull(convexHull *hull, bmeshBall *ballForConvexHull) {
|
||||||
vec3Add(&ballForConvexHull->position, &y, &q.pt[3]);
|
vec3Add(&ballForConvexHull->position, &y, &q.pt[3]);
|
||||||
vec3Add(&q.pt[3], &z, &q.pt[3]);
|
vec3Add(&q.pt[3], &z, &q.pt[3]);
|
||||||
|
|
||||||
convexHullAddVertex(hull, &q.pt[0], ballForConvexHull->index, 0);
|
vertexIndex[0] = convexHullAddVertex(hull, &q.pt[0], ballForConvexHull->index, 0);
|
||||||
convexHullAddVertex(hull, &q.pt[1], ballForConvexHull->index, 1);
|
vertexIndex[1] = convexHullAddVertex(hull, &q.pt[1], ballForConvexHull->index, 1);
|
||||||
convexHullAddVertex(hull, &q.pt[2], ballForConvexHull->index, 2);
|
vertexIndex[2] = convexHullAddVertex(hull, &q.pt[2], ballForConvexHull->index, 2);
|
||||||
convexHullAddVertex(hull, &q.pt[3], ballForConvexHull->index, 3);
|
vertexIndex[3] = convexHullAddVertex(hull, &q.pt[3], ballForConvexHull->index, 3);
|
||||||
|
|
||||||
|
if (*outmostBall) {
|
||||||
|
if (ballForConvexHull->radius > (*outmostBall)->radius) {
|
||||||
|
needUpdateOutmost = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
needUpdateOutmost = 1;
|
||||||
|
}
|
||||||
|
if (needUpdateOutmost) {
|
||||||
|
*outmostBall = ballForConvexHull;
|
||||||
|
*outmostBallFirstVertexIndex = vertexIndex[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
|
@ -548,12 +565,22 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ball->roundColor = bm->roundColor;
|
ball->roundColor = bm->roundColor;
|
||||||
if (BMESH_BALL_TYPE_ROOT == ball->type) {
|
if (BMESH_BALL_TYPE_ROOT == ball->type && 4 == ball->index) {
|
||||||
convexHull *hull = convexHullCreate();
|
tri2QuadContext *t2q;
|
||||||
|
convexHull *hull;
|
||||||
|
bmeshBall *outmostBall = 0;
|
||||||
|
int outmostBallFirstVertexIndex = 0;
|
||||||
|
hull = convexHullCreate();
|
||||||
if (!hull) {
|
if (!hull) {
|
||||||
fprintf(stderr, "%s:convexHullCreate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:convexHullCreate failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
t2q = tri2QuadContextCreate();
|
||||||
|
if (!t2q) {
|
||||||
|
fprintf(stderr, "%s:tri2QuadContextCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
glColor3f(0.0, 0.0, 0.0);
|
glColor3f(0.0, 0.0, 0.0);
|
||||||
drawDebugPrintf("root <%f,%f,%f>", ball->position.x,
|
drawDebugPrintf("root <%f,%f,%f>", ball->position.x,
|
||||||
ball->position.y, ball->position.z);
|
ball->position.y, ball->position.z);
|
||||||
|
@ -561,19 +588,40 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
child;
|
child;
|
||||||
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
|
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
|
||||||
ballForConvexHull = bmeshFindBallForConvexHull(bm, ball, child);
|
ballForConvexHull = bmeshFindBallForConvexHull(bm, ball, child);
|
||||||
addBallToHull(hull, ballForConvexHull);
|
addBallToHull(hull, ballForConvexHull,
|
||||||
|
&outmostBall, &outmostBallFirstVertexIndex);
|
||||||
}
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
addBallToHull(hull, parent);
|
addBallToHull(hull, parent, &outmostBall, &outmostBallFirstVertexIndex);
|
||||||
|
}
|
||||||
|
if (outmostBall) {
|
||||||
|
convexHullAddTodo(hull, outmostBallFirstVertexIndex + 0,
|
||||||
|
outmostBallFirstVertexIndex + 1, outmostBallFirstVertexIndex + 2);
|
||||||
}
|
}
|
||||||
convexHullGenerate(hull);
|
convexHullGenerate(hull);
|
||||||
glPushMatrix();
|
convexHullUnifyNormals(hull, &ball->position);
|
||||||
{
|
{
|
||||||
int triIndex;
|
int triIndex;
|
||||||
glColor3f(1.0f, 1.0f, 1.0f);
|
|
||||||
for (triIndex = 0; triIndex < convexHullGetTriangleNum(hull);
|
for (triIndex = 0; triIndex < convexHullGetTriangleNum(hull);
|
||||||
++triIndex) {
|
++triIndex) {
|
||||||
triangle *tri = (triangle *)convexHullGetTriangle(hull, triIndex);
|
triangle *tri = (triangle *)convexHullGetTriangle(hull, triIndex);
|
||||||
|
tri2QuadAddTriangle(t2q, tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tri2QuadConvert(t2q);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
|
||||||
|
/*
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
{
|
||||||
|
int triIndex;
|
||||||
|
for (triIndex = 0; triIndex < convexHullGetTriangleNum(hull);
|
||||||
|
++triIndex) {
|
||||||
|
triangle *tri = (triangle *)convexHullGetTriangle(hull, triIndex);
|
||||||
|
//if (triIndex > displayTriangleFaceIndex) {
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
drawTriangle(tri);
|
drawTriangle(tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,8 +641,68 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
{
|
||||||
|
int triIndex;
|
||||||
|
for (triIndex = 0; triIndex < tri2QuadGetTriangleNum(t2q);
|
||||||
|
++triIndex) {
|
||||||
|
triangle *tri = (triangle *)tri2QuadGetTriangle(t2q, triIndex);
|
||||||
|
drawTriangle(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glColor3f(0.0f, 0.0f, 0.0f);
|
||||||
|
{
|
||||||
|
int triIndex;
|
||||||
|
int j;
|
||||||
|
for (triIndex = 0; triIndex < tri2QuadGetTriangleNum(t2q);
|
||||||
|
++triIndex) {
|
||||||
|
triangle *tri = (triangle *)tri2QuadGetTriangle(t2q, triIndex);
|
||||||
|
glBegin(GL_LINE_STRIP);
|
||||||
|
for (j = 0; j < 3; ++j) {
|
||||||
|
glVertex3f(tri->pt[j].x, tri->pt[j].y, tri->pt[j].z);
|
||||||
|
}
|
||||||
|
glVertex3f(tri->pt[0].x, tri->pt[0].y, tri->pt[0].z);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
{
|
||||||
|
int quadIndex;
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (quadIndex = 0; quadIndex < tri2QuadGetQuadNum(t2q);
|
||||||
|
++quadIndex) {
|
||||||
|
quad *q = (quad *)tri2QuadGetQuad(t2q, quadIndex);
|
||||||
|
vec3 normal;
|
||||||
|
int j;
|
||||||
|
vec3Normal(&q->pt[0], &q->pt[1], &q->pt[2], &normal);
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
glNormal3f(normal.x, normal.y, normal.z);
|
||||||
|
glVertex3f(q->pt[j].x, q->pt[j].y, q->pt[j].z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
glColor3f(0.0f, 0.0f, 0.0f);
|
||||||
|
{
|
||||||
|
int quadIndex;
|
||||||
|
int j;
|
||||||
|
for (quadIndex = 0; quadIndex < tri2QuadGetQuadNum(t2q);
|
||||||
|
++quadIndex) {
|
||||||
|
quad *q = (quad *)tri2QuadGetQuad(t2q, quadIndex);
|
||||||
|
glBegin(GL_LINE_STRIP);
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
glVertex3f(q->pt[j].x, q->pt[j].y, q->pt[j].z);
|
||||||
|
}
|
||||||
|
glVertex3f(q->pt[0].x, q->pt[0].y, q->pt[0].z);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
convexHullDestroy(hull);
|
convexHullDestroy(hull);
|
||||||
|
tri2QuadContextDestroy(t2q);
|
||||||
}
|
}
|
||||||
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
||||||
child;
|
child;
|
||||||
|
|
271
src/convexhull.c
271
src/convexhull.c
|
@ -3,14 +3,14 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "convexhull.h"
|
#include "convexhull.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "hashtable.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Implement Gift wrapping method which describled in http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf
|
// Implement Gift wrapping method which describled in http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Translate from Danielhst's lua version https://github.com/danielhst/3d-Hull-gift-wrap/blob/master/giftWrap.lua
|
#define TRIANGLE_INDEX_HASHTABLE_SIZE 100
|
||||||
//
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec3 pt;
|
vec3 pt;
|
||||||
|
@ -18,18 +18,50 @@ typedef struct {
|
||||||
int orderOnPlane;
|
int orderOnPlane;
|
||||||
} converHullVertex;
|
} converHullVertex;
|
||||||
|
|
||||||
|
typedef struct face {
|
||||||
|
int indices[3];
|
||||||
|
} face;
|
||||||
|
|
||||||
struct convexHull {
|
struct convexHull {
|
||||||
array *vertexArray;
|
array *vertexArray;
|
||||||
array *openEdgeArray;
|
array *todoArray;
|
||||||
array *triangleArray;
|
array *faceArray;
|
||||||
int nextEdgeIndex;
|
int nextTodoIndex;
|
||||||
unsigned int *openEdgeExistMap;
|
unsigned int *openEdgeExistMap;
|
||||||
|
hashtable *faceHashtable;
|
||||||
|
face findFace;
|
||||||
|
triangle returnTriangle;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int firstVertex;
|
int firstVertex;
|
||||||
int secondVertex;
|
int secondVertex;
|
||||||
} edge;
|
int thirdVertex;
|
||||||
|
} todo;
|
||||||
|
|
||||||
|
face *convexHullGetFaceByHashtableParam(convexHull *hull,
|
||||||
|
const void *param) {
|
||||||
|
int index = (char *)param - (char *)0;
|
||||||
|
if (0 == index) {
|
||||||
|
return &hull->findFace;
|
||||||
|
}
|
||||||
|
return (face *)arrayGetItem(hull->faceArray, index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int faceHash(void *userData, const void *node) {
|
||||||
|
face *triIdx = convexHullGetFaceByHashtableParam(
|
||||||
|
(convexHull *)userData, node);
|
||||||
|
return triIdx->indices[0] * triIdx->indices[1] * triIdx->indices[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int faceCompare(void *userData, const void *node1,
|
||||||
|
const void *node2) {
|
||||||
|
face *triIdx1 = convexHullGetFaceByHashtableParam(
|
||||||
|
(convexHull *)userData, node1);
|
||||||
|
face *triIdx2 = convexHullGetFaceByHashtableParam(
|
||||||
|
(convexHull *)userData, node2);
|
||||||
|
return memcmp(triIdx1, triIdx2, sizeof(face));
|
||||||
|
}
|
||||||
|
|
||||||
convexHull *convexHullCreate(void) {
|
convexHull *convexHullCreate(void) {
|
||||||
convexHull *hull = (convexHull *)calloc(1, sizeof(convexHull));
|
convexHull *hull = (convexHull *)calloc(1, sizeof(convexHull));
|
||||||
|
@ -40,16 +72,26 @@ convexHull *convexHullCreate(void) {
|
||||||
hull->vertexArray = arrayCreate(sizeof(converHullVertex));
|
hull->vertexArray = arrayCreate(sizeof(converHullVertex));
|
||||||
if (!hull->vertexArray) {
|
if (!hull->vertexArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
hull->openEdgeArray = arrayCreate(sizeof(edge));
|
hull->todoArray = arrayCreate(sizeof(todo));
|
||||||
if (!hull->openEdgeArray) {
|
if (!hull->todoArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
hull->triangleArray = arrayCreate(sizeof(triangle));
|
hull->faceArray = arrayCreate(sizeof(face));
|
||||||
if (!hull->triangleArray) {
|
if (!hull->faceArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hull->faceHashtable = hashtableCreate(TRIANGLE_INDEX_HASHTABLE_SIZE,
|
||||||
|
faceHash, faceCompare, hull);
|
||||||
|
if (!hull->faceHashtable) {
|
||||||
|
fprintf(stderr, "%s:hashtableCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return hull;
|
return hull;
|
||||||
|
@ -65,10 +107,13 @@ void convexHullMarkEdgeAsExsits(convexHull *hull, int firstVertex,
|
||||||
|
|
||||||
int convexHullEdgeExsits(convexHull *hull, int firstVertex,
|
int convexHullEdgeExsits(convexHull *hull, int firstVertex,
|
||||||
int secondVertex) {
|
int secondVertex) {
|
||||||
|
if (hull->openEdgeExistMap) {
|
||||||
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
||||||
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
||||||
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
||||||
return hull->openEdgeExistMap[unitIndex] & (0x00000001 << unitOffset);
|
return hull->openEdgeExistMap[unitIndex] & (0x00000001 << unitOffset);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
|
int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
|
||||||
|
@ -86,31 +131,24 @@ int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
|
||||||
return newVertex;
|
return newVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullAddOpenEdgeNoCheck(convexHull *hull, int firstVertex,
|
int convexHullAddTodoNoCheck(convexHull *hull, int firstVertex,
|
||||||
int secondVertex) {
|
int secondVertex, int thirdVertex) {
|
||||||
edge *e;
|
todo *t;
|
||||||
int newEdge = arrayGetLength(hull->openEdgeArray);
|
int newEdge = arrayGetLength(hull->todoArray);
|
||||||
if (firstVertex < 0 || secondVertex < 0) {
|
if (firstVertex < 0 || secondVertex < 0) {
|
||||||
fprintf(stderr, "%s:Invalid params(firstVertex:%d secondVertex:%d).\n",
|
fprintf(stderr, "%s:Invalid params(firstVertex:%d secondVertex:%d).\n",
|
||||||
__FUNCTION__, firstVertex, secondVertex);
|
__FUNCTION__, firstVertex, secondVertex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (0 != arraySetLength(hull->openEdgeArray, newEdge + 1)) {
|
if (0 != arraySetLength(hull->todoArray, newEdge + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
e = (edge *)arrayGetItem(hull->openEdgeArray, newEdge);
|
t = (todo *)arrayGetItem(hull->todoArray, newEdge);
|
||||||
memset(e, 0, sizeof(edge));
|
memset(t, 0, sizeof(todo));
|
||||||
e->firstVertex = firstVertex;
|
t->firstVertex = firstVertex;
|
||||||
e->secondVertex = secondVertex;
|
t->secondVertex = secondVertex;
|
||||||
return 0;
|
t->thirdVertex = thirdVertex;
|
||||||
}
|
|
||||||
|
|
||||||
int convexHullAddEdge(convexHull *hull, int p1, int p2) {
|
|
||||||
convexHullMarkEdgeAsExsits(hull, p1, p2);
|
|
||||||
if (!convexHullEdgeExsits(hull, p2, p1)) {
|
|
||||||
return convexHullAddOpenEdgeNoCheck(hull, p2, p1);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,9 +157,15 @@ static int isInAdjacentOrder(int order1, int order2) {
|
||||||
(order2 + 1) % 4 == order1);
|
(order2 + 1) % 4 == order1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullAddTriangle(convexHull *hull, int firstVertex, int secondVertex,
|
static int sortface(const void *first, const void *second) {
|
||||||
|
const int *firstIndex = (const void *)first;
|
||||||
|
const int *secondIndex = (const void *)second;
|
||||||
|
return *firstIndex - *secondIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convexHullAddFace(convexHull *hull, int firstVertex, int secondVertex,
|
||||||
int thirdVertex) {
|
int thirdVertex) {
|
||||||
triangle *tri;
|
face *tri;
|
||||||
converHullVertex *vtx1;
|
converHullVertex *vtx1;
|
||||||
converHullVertex *vtx2;
|
converHullVertex *vtx2;
|
||||||
converHullVertex *vtx3;
|
converHullVertex *vtx3;
|
||||||
|
@ -147,16 +191,26 @@ int convexHullAddTriangle(convexHull *hull, int firstVertex, int secondVertex,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newTri = arrayGetLength(hull->triangleArray);
|
memset(&hull->findFace, 0, sizeof(hull->findFace));
|
||||||
if (0 != arraySetLength(hull->triangleArray, newTri + 1)) {
|
hull->findFace.indices[0] = firstVertex;
|
||||||
|
hull->findFace.indices[1] = secondVertex;
|
||||||
|
hull->findFace.indices[2] = thirdVertex;
|
||||||
|
if (0 == hashtableGet(hull->faceHashtable, 0)) {
|
||||||
|
qsort(hull->findFace.indices, 3,
|
||||||
|
sizeof(hull->findFace.indices[0]), sortface);
|
||||||
|
newTri = arrayGetLength(hull->faceArray);
|
||||||
|
if (0 != arraySetLength(hull->faceArray, newTri + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
tri = (triangle *)arrayGetItem(hull->triangleArray, newTri);
|
tri = (face *)arrayGetItem(hull->faceArray, newTri);
|
||||||
memset(tri, 0, sizeof(triangle));
|
*tri = hull->findFace;
|
||||||
tri->pt[0] = vtx1->pt;
|
if (0 != hashtableInsert(hull->faceHashtable,
|
||||||
tri->pt[1] = vtx2->pt;
|
(char *)0 + newTri + 1)) {
|
||||||
tri->pt[2] = vtx3->pt;
|
fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +221,9 @@ static void convexHullReleaseForGenerate(convexHull *hull) {
|
||||||
|
|
||||||
void convexHullDestroy(convexHull *hull) {
|
void convexHullDestroy(convexHull *hull) {
|
||||||
arrayDestroy(hull->vertexArray);
|
arrayDestroy(hull->vertexArray);
|
||||||
arrayDestroy(hull->openEdgeArray);
|
arrayDestroy(hull->todoArray);
|
||||||
arrayDestroy(hull->triangleArray);
|
arrayDestroy(hull->faceArray);
|
||||||
|
hashtableDestroy(hull->faceHashtable);
|
||||||
convexHullReleaseForGenerate(hull);
|
convexHullReleaseForGenerate(hull);
|
||||||
free(hull);
|
free(hull);
|
||||||
}
|
}
|
||||||
|
@ -183,60 +238,45 @@ static int convexHullPrepareForGenerate(convexHull *hull) {
|
||||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
hull->nextEdgeIndex = 0;
|
hull->nextTodoIndex = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullGetLower(convexHull *hull) {
|
int convexHullGetNextVertex(convexHull *hull, int p1Index, int p2Index,
|
||||||
int index = 0;
|
int p3Index) {
|
||||||
|
vec3 *p1 = (vec3 *)arrayGetItem(hull->vertexArray, p1Index);
|
||||||
|
vec3 *p2 = (vec3 *)arrayGetItem(hull->vertexArray, p2Index);
|
||||||
|
vec3 *p3 = (vec3 *)arrayGetItem(hull->vertexArray, p3Index);
|
||||||
|
vec3 beginNormal;
|
||||||
|
vec3 endNormal;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < arrayGetLength(hull->vertexArray); ++i) {
|
float angle;
|
||||||
vec3 *pI = (vec3 *)arrayGetItem(hull->vertexArray, i);
|
float maxAngle = 0;
|
||||||
vec3 *pIndex = (vec3 *)arrayGetItem(hull->vertexArray, index);
|
int candidateIndex = -1;
|
||||||
if (pI->z < pIndex->z) {
|
|
||||||
index = i;
|
vec3Normal(p1, p2, p3, &beginNormal);
|
||||||
} else if (pI->z == pIndex->z) {
|
|
||||||
if (pI->y < pIndex->y) {
|
for (i = 0; i < arrayGetLength(hull->vertexArray); ++i) {
|
||||||
index = i;
|
if (i != p1Index && i != p2Index && i != p3Index) {
|
||||||
} else if (pI->x < pIndex->x) {
|
vec3Normal(p1, p2, (vec3 *)arrayGetItem(hull->vertexArray, i),
|
||||||
index = i;
|
&endNormal);
|
||||||
|
angle = vec3Angle(&beginNormal, &endNormal);
|
||||||
|
if (angle > maxAngle) {
|
||||||
|
candidateIndex = i;
|
||||||
|
maxAngle = angle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
|
||||||
|
return candidateIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullGetNextVertex(convexHull *hull, int p1Index, int p2Index) {
|
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2,
|
||||||
vec3 pCorner = {1, 1, 0};
|
int vertex3) {
|
||||||
vec3 *p1 = (vec3 *)arrayGetItem(hull->vertexArray, p1Index);
|
if (!convexHullEdgeExsits(hull, vertex1, vertex2)) {
|
||||||
vec3 *p2 = p2Index < 0 ? &pCorner : (vec3 *)arrayGetItem(hull->vertexArray,
|
return convexHullAddTodoNoCheck(hull, vertex1, vertex2, vertex3);
|
||||||
p2Index);
|
|
||||||
vec3 edge;
|
|
||||||
int candidateIndex = -1;
|
|
||||||
int i;
|
|
||||||
vec3Sub(p2, p1, &edge);
|
|
||||||
vec3Normalize(&edge);
|
|
||||||
for (i = 0; i < arrayGetLength(hull->vertexArray); ++i) {
|
|
||||||
if (i != p1Index && i != p2Index) {
|
|
||||||
if (-1 == candidateIndex) {
|
|
||||||
candidateIndex = 0;
|
|
||||||
} else {
|
|
||||||
vec3 v, proj, candidate, canProj, cross;
|
|
||||||
vec3Sub((vec3 *)arrayGetItem(hull->vertexArray, i), p1, &v);
|
|
||||||
vec3ProjectOver(&v, &edge, &proj);
|
|
||||||
vec3Sub(&v, &proj, &v);
|
|
||||||
vec3Sub((vec3 *)arrayGetItem(hull->vertexArray,
|
|
||||||
candidateIndex), p1, &candidate);
|
|
||||||
vec3ProjectOver(&candidate, &edge, &canProj);
|
|
||||||
vec3Sub(&candidate, &canProj, &candidate);
|
|
||||||
vec3CrossProduct(&candidate, &v, &cross);
|
|
||||||
if (vec3DotProduct(&cross, &edge) > 0) {
|
|
||||||
candidateIndex = i;
|
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
return candidateIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullGenerate(convexHull *hull) {
|
int convexHullGenerate(convexHull *hull) {
|
||||||
|
@ -246,34 +286,63 @@ int convexHullGenerate(convexHull *hull) {
|
||||||
fprintf(stderr, "%s:convexHullPrepareForGenerate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:convexHullPrepareForGenerate failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
index1 = convexHullGetLower(hull);
|
while (hull->nextTodoIndex < arrayGetLength(hull->todoArray)) {
|
||||||
index2 = convexHullGetNextVertex(hull, index1, -1);
|
todo *t = (todo *)arrayGetItem(hull->todoArray, hull->nextTodoIndex++);
|
||||||
convexHullAddEdge(hull, index2, index1);
|
index1 = t->firstVertex;
|
||||||
//glColor3f(0.0, 0.0, 0.0);
|
index2 = t->secondVertex;
|
||||||
//drawDebugPrintf("edgeLength:%d", arrayGetLength(hull->openEdgeArray));
|
|
||||||
while (hull->nextEdgeIndex < arrayGetLength(hull->openEdgeArray)) {
|
|
||||||
edge *e = (edge *)arrayGetItem(hull->openEdgeArray, hull->nextEdgeIndex++);
|
|
||||||
index1 = e->firstVertex;
|
|
||||||
index2 = e->secondVertex;
|
|
||||||
if (convexHullEdgeExsits(hull, index1, index2)) {
|
if (convexHullEdgeExsits(hull, index1, index2)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
convexHullMarkEdgeAsExsits(hull, index1, index2);
|
convexHullMarkEdgeAsExsits(hull, index1, index2);
|
||||||
index3 = convexHullGetNextVertex(hull, index1, index2);
|
index3 = convexHullGetNextVertex(hull, index1, index2, t->thirdVertex);
|
||||||
//drawDebugPrintf("%d,%d,%d", index1, index2, index3);
|
if (-1 == index3) {
|
||||||
convexHullAddTriangle(hull, index1, index2, index3);
|
continue;
|
||||||
convexHullAddEdge(hull, index1, index2);
|
}
|
||||||
convexHullAddEdge(hull, index2, index3);
|
convexHullAddFace(hull, index1, index2, index3);
|
||||||
convexHullAddEdge(hull, index3, index1);
|
convexHullAddTodo(hull, index1, index2, index3);
|
||||||
|
convexHullAddTodo(hull, index2, index3, index1);
|
||||||
|
convexHullAddTodo(hull, index3, index1, index2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convexHullUnifyNormals(convexHull *hull, vec3 *origin) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < arrayGetLength(hull->faceArray); ++i) {
|
||||||
|
face *triIdx = (face *)arrayGetItem(
|
||||||
|
hull->faceArray, i);
|
||||||
|
converHullVertex *p1 = (converHullVertex *)arrayGetItem(
|
||||||
|
hull->vertexArray, triIdx->indices[0]);
|
||||||
|
converHullVertex *p2 = (converHullVertex *)arrayGetItem(
|
||||||
|
hull->vertexArray, triIdx->indices[1]);
|
||||||
|
converHullVertex *p3 = (converHullVertex *)arrayGetItem(
|
||||||
|
hull->vertexArray, triIdx->indices[2]);
|
||||||
|
vec3 normal;
|
||||||
|
vec3 o2v;
|
||||||
|
vec3Normal(&p1->pt, &p2->pt, &p3->pt, &normal);
|
||||||
|
vec3Sub(&p1->pt, origin, &o2v);
|
||||||
|
if (vec3DotProduct(&o2v, &normal) < 0) {
|
||||||
|
int index = triIdx->indices[0];
|
||||||
|
triIdx->indices[0] = triIdx->indices[2];
|
||||||
|
triIdx->indices[2] = index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullGetTriangleNum(convexHull *hull) {
|
int convexHullGetTriangleNum(convexHull *hull) {
|
||||||
return arrayGetLength(hull->triangleArray);
|
return arrayGetLength(hull->faceArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
triangle *convexHullGetTriangle(convexHull *hull, int index) {
|
triangle *convexHullGetTriangle(convexHull *hull, int index) {
|
||||||
triangle *tri = (triangle *)arrayGetItem(hull->triangleArray, index);
|
int i;
|
||||||
return tri;
|
face *triIdx = (face *)arrayGetItem(
|
||||||
|
hull->faceArray, index);
|
||||||
|
memset(&hull->returnTriangle, 0, sizeof(hull->returnTriangle));
|
||||||
|
for (i = 0; i < 3; ++i) {
|
||||||
|
converHullVertex *vertex = (converHullVertex *)arrayGetItem(
|
||||||
|
hull->vertexArray, triIdx->indices[i]);
|
||||||
|
hull->returnTriangle.pt[i] = vertex->pt;
|
||||||
|
}
|
||||||
|
return &hull->returnTriangle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@ int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
|
||||||
int orderOnPlane);
|
int orderOnPlane);
|
||||||
void convexHullDestroy(convexHull *hull);
|
void convexHullDestroy(convexHull *hull);
|
||||||
int convexHullGenerate(convexHull *hull);
|
int convexHullGenerate(convexHull *hull);
|
||||||
|
int convexHullUnifyNormals(convexHull *hull, vec3 *origin);
|
||||||
int convexHullGetTriangleNum(convexHull *hull);
|
int convexHullGetTriangleNum(convexHull *hull);
|
||||||
triangle *convexHullGetTriangle(convexHull *hull, int index);
|
triangle *convexHullGetTriangle(convexHull *hull, int index);
|
||||||
|
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2, int vertex3);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "hashtable.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
typedef struct hashtableEntry {
|
||||||
|
const void *node;
|
||||||
|
int nextEntryIndex;
|
||||||
|
} hashtableEntry;
|
||||||
|
|
||||||
|
typedef struct hashtableKey {
|
||||||
|
int entryNum;
|
||||||
|
int firstEntryIndex;
|
||||||
|
} hashtableKey;
|
||||||
|
|
||||||
|
struct hashtable {
|
||||||
|
array *keyArray;
|
||||||
|
array *entryArray;
|
||||||
|
int bucketSize;
|
||||||
|
int (*hashCallback)(void *userData, const void *node);
|
||||||
|
int (*compareCallback)(void *userData, const void *node1, const void *node2);
|
||||||
|
void *userData;
|
||||||
|
};
|
||||||
|
|
||||||
|
hashtable *hashtableCreate(int bucketSize,
|
||||||
|
int (*hashCallback)(void *userData, const void *node),
|
||||||
|
int (*compareCallback)(void *userData, const void *node1,
|
||||||
|
const void *node2),
|
||||||
|
void *userData) {
|
||||||
|
hashtable *ht = (hashtable *)calloc(1, sizeof(hashtable));
|
||||||
|
if (!ht) {
|
||||||
|
fprintf(stderr, "%s:Insufficient memory.", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ht->keyArray = arrayCreate(sizeof(hashtableKey));
|
||||||
|
if (!ht->keyArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
hashtableDestroy(ht);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ht->entryArray = arrayCreate(sizeof(hashtableEntry));
|
||||||
|
if (!ht->entryArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
hashtableDestroy(ht);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ht->bucketSize = bucketSize;
|
||||||
|
ht->hashCallback = hashCallback;
|
||||||
|
ht->compareCallback = compareCallback;
|
||||||
|
ht->userData = userData;
|
||||||
|
if (0 != arraySetLength(ht->keyArray, bucketSize)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed(bucketSize:%d).", __FUNCTION__,
|
||||||
|
bucketSize);
|
||||||
|
hashtableDestroy(ht);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashtableDestroy(hashtable *ht) {
|
||||||
|
if (ht) {
|
||||||
|
arrayDestroy(ht->keyArray);
|
||||||
|
arrayDestroy(ht->entryArray);
|
||||||
|
free(ht);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hashtableGetNodeHash(hashtable *ht, const void *node) {
|
||||||
|
return (int)((unsigned int)ht->hashCallback(ht->userData,
|
||||||
|
node) % ht->bucketSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static hashtableEntry *findEntry(hashtable *ht, hashtableKey *key,
|
||||||
|
const void *node) {
|
||||||
|
int i;
|
||||||
|
int nextEntryIndex = key->firstEntryIndex;
|
||||||
|
for (i = 0; i < key->entryNum; ++i) {
|
||||||
|
hashtableEntry *entry;
|
||||||
|
assert(-1 != nextEntryIndex);
|
||||||
|
entry = (hashtableEntry *)arrayGetItem(ht->entryArray, nextEntryIndex);
|
||||||
|
if (0 == ht->compareCallback(ht->userData, entry->node, node)) {
|
||||||
|
return (void *)entry->node;
|
||||||
|
}
|
||||||
|
nextEntryIndex = entry->nextEntryIndex;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hashtableInsert(hashtable *ht, const void *node) {
|
||||||
|
int newEntryIndex;
|
||||||
|
int hash = hashtableGetNodeHash(ht, node);
|
||||||
|
hashtableKey *key = (hashtableKey *)arrayGetItem(ht->keyArray, hash);
|
||||||
|
hashtableEntry *entry = findEntry(ht, key, node);
|
||||||
|
if (entry) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
newEntryIndex = arrayGetLength(ht->entryArray);
|
||||||
|
if (0 != arraySetLength(ht->entryArray, newEntryIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed(newEntryIndex:%d).",
|
||||||
|
__FUNCTION__, newEntryIndex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
entry = (hashtableEntry *)arrayGetItem(ht->entryArray, newEntryIndex);
|
||||||
|
entry->node = node;
|
||||||
|
entry->nextEntryIndex = 0 == key->entryNum ? -1 : key->firstEntryIndex;
|
||||||
|
key->firstEntryIndex = newEntryIndex;
|
||||||
|
key->entryNum++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hashtableGet(hashtable *ht, const void *node) {
|
||||||
|
int hash = hashtableGetNodeHash(ht, node);
|
||||||
|
hashtableKey *key = (hashtableKey *)arrayGetItem(ht->keyArray, hash);
|
||||||
|
return findEntry(ht, key, node);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef HASHTABLE_H
|
||||||
|
#define HASHTABLE_H
|
||||||
|
|
||||||
|
typedef struct hashtable hashtable;
|
||||||
|
|
||||||
|
hashtable *hashtableCreate(int bucketSize,
|
||||||
|
int (*hashCallback)(void *userData, const void *node),
|
||||||
|
int (*compareCallback)(void *userData, const void *node1, const void *node2),
|
||||||
|
void *userData);
|
||||||
|
void hashtableDestroy(hashtable *ht);
|
||||||
|
int hashtableInsert(hashtable *ht, const void *node);
|
||||||
|
void *hashtableGet(hashtable *ht, const void *node);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "vector3d.h"
|
#include "vector3d.h"
|
||||||
|
|
||||||
static const float bmeshBallColors[][3] {
|
static const float bmeshBallColors[][4] {
|
||||||
{0, 0.78, 1},
|
{0.00, 0.78, 1.00, 0.5},
|
||||||
{1, 0, 0},
|
{1.00, 0.00, 0.00, 0.5},
|
||||||
{1, 1, 1}
|
{1.00, 1.00, 1.00, 0.5}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const float bmeshBoneColor[3] = {1, 1, 0};
|
static const float bmeshBoneColor[3] = {1, 1, 0};
|
||||||
|
@ -27,11 +27,14 @@ int drawDebugPrintf(const char *fmt, ...) {
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(text, sizeof(text), fmt, args);
|
vsnprintf(text, sizeof(text), fmt, args);
|
||||||
debugOutputTop += 9;
|
debugOutputTop += 9;
|
||||||
|
if (debugOutputTop > 200) {
|
||||||
|
debugOutputTop = 0;
|
||||||
|
}
|
||||||
return drawText(x, y, text);
|
return drawText(x, y, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int drawBmeshBall(bmesh *bm, bmeshBall *ball) {
|
static int drawBmeshBall(bmesh *bm, bmeshBall *ball) {
|
||||||
glColor3fv(bmeshBallColors[ball->type]);
|
glColor4fv(bmeshBallColors[ball->type]);
|
||||||
drawSphere(&ball->position, ball->radius, 36, 24);
|
drawSphere(&ball->position, ball->radius, 36, 24);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +132,7 @@ static void drawBmeshBallQuadRecursively(bmesh *bm, bmeshBall *ball) {
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
drawBmeshBallQuad(ball);
|
//drawBmeshBallQuad(ball);
|
||||||
|
|
||||||
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
|
||||||
child;
|
child;
|
||||||
|
@ -277,7 +280,7 @@ void Render::paintGL() {
|
||||||
|
|
||||||
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
|
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
|
||||||
bmeshBone *bone = bmeshGetBone(bm, index);
|
bmeshBone *bone = bmeshGetBone(bm, index);
|
||||||
drawBmeshBone(bm, bone);
|
//drawBmeshBone(bm, bone);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "tri2quad.h"
|
||||||
|
#include "vector3d.h"
|
||||||
|
#include "array.h"
|
||||||
|
#include "hashtable.h"
|
||||||
|
|
||||||
|
#define EDGE_HASHTABLE_SIZE 100
|
||||||
|
|
||||||
|
typedef struct edge {
|
||||||
|
vec3 p1;
|
||||||
|
vec3 p2;
|
||||||
|
int inputA;
|
||||||
|
int inputB;
|
||||||
|
int score;
|
||||||
|
} edge;
|
||||||
|
|
||||||
|
typedef struct inputTriangle {
|
||||||
|
triangle tri;
|
||||||
|
float area;
|
||||||
|
vec3 normal;
|
||||||
|
int merged;
|
||||||
|
} inputTriangle;
|
||||||
|
|
||||||
|
struct tri2QuadContext {
|
||||||
|
array *inputArray;
|
||||||
|
array *triangleArray;
|
||||||
|
array *quadArray;
|
||||||
|
array *edgeArray;
|
||||||
|
hashtable *edgeHashtable;
|
||||||
|
edge findEdge;
|
||||||
|
};
|
||||||
|
|
||||||
|
static edge *tri2QuadGetEdgeByHashtableParam(tri2QuadContext *ctx,
|
||||||
|
const void *param) {
|
||||||
|
int edgeIndex = (char *)param - (char *)0;
|
||||||
|
if (0 == edgeIndex) {
|
||||||
|
return &ctx->findEdge;
|
||||||
|
}
|
||||||
|
return (edge *)arrayGetItem(ctx->edgeArray, edgeIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edgeHash(void *userData, const void *node) {
|
||||||
|
edge *e = tri2QuadGetEdgeByHashtableParam((tri2QuadContext *)userData, node);
|
||||||
|
return (int)(e->p1.x + 1) * (e->p1.y + 1) * (e->p1.z + 1) *
|
||||||
|
(e->p2.x + 1) * (e->p2.y + 1) * (e->p2.z + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edgeCompare(void *userData, const void *node1, const void *node2) {
|
||||||
|
const edge *e1 = (const edge *)tri2QuadGetEdgeByHashtableParam(
|
||||||
|
(tri2QuadContext *)userData, node1);
|
||||||
|
const edge *e2 = (const edge *)tri2QuadGetEdgeByHashtableParam(
|
||||||
|
(tri2QuadContext *)userData, node2);
|
||||||
|
if ((0 == memcmp(&e1->p1, &e2->p1, sizeof(e1->p1)) &&
|
||||||
|
0 == memcmp(&e1->p2, &e2->p2, sizeof(e1->p1))) ||
|
||||||
|
(0 == memcmp(&e1->p1, &e2->p2, sizeof(e1->p1)) &&
|
||||||
|
0 == memcmp(&e1->p2, &e2->p1, sizeof(e1->p1)))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tri2QuadContext *tri2QuadContextCreate(void) {
|
||||||
|
tri2QuadContext *ctx = (tri2QuadContext *)calloc(1, sizeof(tri2QuadContext));
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "%s:Insufficient memory.", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ctx->inputArray = arrayCreate(sizeof(inputTriangle));
|
||||||
|
if (!ctx->inputArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
tri2QuadContextDestroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ctx->triangleArray = arrayCreate(sizeof(triangle));
|
||||||
|
if (!ctx->triangleArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
tri2QuadContextDestroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ctx->quadArray = arrayCreate(sizeof(quad));
|
||||||
|
if (!ctx->quadArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
tri2QuadContextDestroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ctx->edgeHashtable = hashtableCreate(EDGE_HASHTABLE_SIZE, edgeHash,
|
||||||
|
edgeCompare, ctx);
|
||||||
|
if (!ctx->edgeHashtable) {
|
||||||
|
fprintf(stderr, "%s:hashtableCreate failed.", __FUNCTION__);
|
||||||
|
tri2QuadContextDestroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ctx->edgeArray = arrayCreate(sizeof(edge));
|
||||||
|
if (!ctx->edgeArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
||||||
|
tri2QuadContextDestroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tri2QuadAddTriangle(tri2QuadContext *ctx, triangle *tri) {
|
||||||
|
int newInputIndex;
|
||||||
|
inputTriangle *newInput;
|
||||||
|
newInputIndex = arrayGetLength(ctx->inputArray);
|
||||||
|
if (0 != arraySetLength(ctx->inputArray, newInputIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed.", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
newInput = (inputTriangle *)arrayGetItem(ctx->inputArray, newInputIndex);
|
||||||
|
newInput->merged = 0;
|
||||||
|
newInput->tri = *tri;
|
||||||
|
newInput->area = vec3TriangleArea(&tri->pt[0], &tri->pt[1], &tri->pt[2]);
|
||||||
|
vec3Normal(&tri->pt[0], &tri->pt[1], &tri->pt[2], &newInput->normal);
|
||||||
|
return newInputIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static edge *tri2QuadFindEdge(tri2QuadContext *ctx,
|
||||||
|
vec3 *p1, vec3 *p2) {
|
||||||
|
int edgeIndex;
|
||||||
|
ctx->findEdge.p1 = *p1;
|
||||||
|
ctx->findEdge.p2 = *p2;
|
||||||
|
edgeIndex = (char *)hashtableGet(ctx->edgeHashtable, (char *)0) - (char *)0;
|
||||||
|
if (0 == edgeIndex) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (edge *)arrayGetItem(ctx->edgeArray, edgeIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tri2QuadAddInitialEdge(tri2QuadContext *ctx,
|
||||||
|
vec3 *p1, vec3 *p2, int inputIndex) {
|
||||||
|
edge *existedEdge = tri2QuadFindEdge(ctx, p1, p2);
|
||||||
|
if (!existedEdge) {
|
||||||
|
edge *newEdge;
|
||||||
|
int newEdgeIndex = arrayGetLength(ctx->edgeArray);
|
||||||
|
if (0 != arraySetLength(ctx->edgeArray, newEdgeIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed(newEdgeIndex:%d).",
|
||||||
|
__FUNCTION__, newEdgeIndex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
newEdge = (edge *)arrayGetItem(ctx->edgeArray, newEdgeIndex);
|
||||||
|
newEdge->p1 = *p1;
|
||||||
|
newEdge->p2 = *p2;
|
||||||
|
if (0 != hashtableInsert(ctx->edgeHashtable,
|
||||||
|
(char *)0 + newEdgeIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:hashtableInsert failed.", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
newEdge->inputA = inputIndex;
|
||||||
|
newEdge->inputB = -1;
|
||||||
|
newEdge->score = 0;
|
||||||
|
} else {
|
||||||
|
existedEdge->inputB = inputIndex;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tri2QuadAddOutputQuad(tri2QuadContext *ctx, vec3 *first,
|
||||||
|
vec3 *second, vec3 *third, vec3 *fourth) {
|
||||||
|
quad *q;
|
||||||
|
int newQuadIndex = arrayGetLength(ctx->quadArray);
|
||||||
|
if (0 != arraySetLength(ctx->quadArray, newQuadIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed(newQuadIndex:%d).", __FUNCTION__,
|
||||||
|
newQuadIndex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
q = (quad *)arrayGetItem(ctx->quadArray, newQuadIndex);
|
||||||
|
memset(q, 0, sizeof(quad));
|
||||||
|
q->pt[0] = *first;
|
||||||
|
q->pt[1] = *second;
|
||||||
|
q->pt[2] = *third;
|
||||||
|
q->pt[3] = *fourth;
|
||||||
|
return newQuadIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tri2QuadAddOutputTriangle(tri2QuadContext *ctx, vec3 *first,
|
||||||
|
vec3 *second, vec3 *third) {
|
||||||
|
triangle *tri;
|
||||||
|
int newTriangleIndex = arrayGetLength(ctx->triangleArray);
|
||||||
|
if (0 != arraySetLength(ctx->triangleArray, newTriangleIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed(newTriangleIndex:%d).",
|
||||||
|
__FUNCTION__, newTriangleIndex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tri = (triangle *)arrayGetItem(ctx->triangleArray, newTriangleIndex);
|
||||||
|
memset(tri, 0, sizeof(triangle));
|
||||||
|
tri->pt[0] = *first;
|
||||||
|
tri->pt[1] = *second;
|
||||||
|
tri->pt[2] = *third;
|
||||||
|
return newTriangleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tri2QuadAddOutputQuadByEdgeAndInput(tri2QuadContext *ctx, edge *e,
|
||||||
|
inputTriangle *input1, inputTriangle *input2) {
|
||||||
|
vec3 outputPt[4];
|
||||||
|
int i;
|
||||||
|
int nextSaveToIndex;
|
||||||
|
memset(outputPt, 0, sizeof(outputPt));
|
||||||
|
nextSaveToIndex = 0;
|
||||||
|
for (i = 0; i < 3; ++i) {
|
||||||
|
vec3 *pt = &input1->tri.pt[i];
|
||||||
|
if (0 == memcmp(&e->p1, pt, sizeof(e->p1))) {
|
||||||
|
outputPt[nextSaveToIndex] = *pt;
|
||||||
|
nextSaveToIndex += 2;
|
||||||
|
} else if (0 == memcmp(&e->p2, pt, sizeof(e->p2))) {
|
||||||
|
outputPt[nextSaveToIndex] = *pt;
|
||||||
|
nextSaveToIndex += 2;
|
||||||
|
} else {
|
||||||
|
outputPt[1] = *pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; ++i) {
|
||||||
|
vec3 *pt = &input2->tri.pt[i];
|
||||||
|
if (0 != memcmp(&e->p1, pt, sizeof(e->p1)) &&
|
||||||
|
0 != memcmp(&e->p2, pt, sizeof(e->p2))) {
|
||||||
|
outputPt[3] = *pt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tri2QuadAddOutputQuad(ctx, &outputPt[0], &outputPt[1],
|
||||||
|
&outputPt[2], &outputPt[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sortEdgeByScoreDesc(const void *first, const void *second) {
|
||||||
|
const edge *e1 = (const edge *)first;
|
||||||
|
const edge *e2 = (const edge *)second;
|
||||||
|
return e2->score - e1->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tri2QuadConvert(tri2QuadContext *ctx) {
|
||||||
|
int inputIndex;
|
||||||
|
int edgeIndex;
|
||||||
|
|
||||||
|
for (inputIndex = 0; inputIndex < arrayGetLength(ctx->inputArray);
|
||||||
|
++inputIndex) {
|
||||||
|
inputTriangle *inputItem = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
inputIndex);
|
||||||
|
tri2QuadAddInitialEdge(ctx, &inputItem->tri.pt[0], &inputItem->tri.pt[1],
|
||||||
|
inputIndex);
|
||||||
|
tri2QuadAddInitialEdge(ctx, &inputItem->tri.pt[1], &inputItem->tri.pt[2],
|
||||||
|
inputIndex);
|
||||||
|
tri2QuadAddInitialEdge(ctx, &inputItem->tri.pt[2], &inputItem->tri.pt[0],
|
||||||
|
inputIndex);
|
||||||
|
}
|
||||||
|
for (edgeIndex = 0; edgeIndex < arrayGetLength(ctx->edgeArray); ++edgeIndex) {
|
||||||
|
edge *e = (edge *)arrayGetItem(ctx->edgeArray, edgeIndex);
|
||||||
|
inputTriangle *input1;
|
||||||
|
inputTriangle *input2;
|
||||||
|
if (-1 != e->inputA && -1 != e->inputB) {
|
||||||
|
input1 = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
e->inputA);
|
||||||
|
input2 = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
e->inputB);
|
||||||
|
e->score = (int)((input1->area + input2->area) *
|
||||||
|
vec3DotProduct(&input1->normal, &input2->normal) * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qsort(arrayGetItem(ctx->edgeArray, 0), arrayGetLength(ctx->edgeArray),
|
||||||
|
sizeof(edge), sortEdgeByScoreDesc);
|
||||||
|
|
||||||
|
//
|
||||||
|
// After qsort, the edge indices inside the hashtable are no longer right.
|
||||||
|
//
|
||||||
|
|
||||||
|
hashtableDestroy(ctx->edgeHashtable);
|
||||||
|
ctx->edgeHashtable = 0;
|
||||||
|
|
||||||
|
for (edgeIndex = 0; edgeIndex < arrayGetLength(ctx->edgeArray); ++edgeIndex) {
|
||||||
|
edge *e = (edge *)arrayGetItem(ctx->edgeArray, edgeIndex);
|
||||||
|
inputTriangle *input1;
|
||||||
|
inputTriangle *input2;
|
||||||
|
if (-1 != e->inputA && -1 != e->inputB) {
|
||||||
|
input1 = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
e->inputA);
|
||||||
|
input2 = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
e->inputB);
|
||||||
|
if (!input1->merged && !input2->merged) {
|
||||||
|
//input1->merged = 1;
|
||||||
|
//input2->merged = 1;
|
||||||
|
//tri2QuadAddOutputQuadByEdgeAndInput(ctx, e, input1, input2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (inputIndex = 0; inputIndex < arrayGetLength(ctx->inputArray);
|
||||||
|
++inputIndex) {
|
||||||
|
inputTriangle *inputItem = (inputTriangle *)arrayGetItem(ctx->inputArray,
|
||||||
|
inputIndex);
|
||||||
|
if (!inputItem->merged) {
|
||||||
|
tri2QuadAddOutputTriangle(ctx, &inputItem->tri.pt[0],
|
||||||
|
&inputItem->tri.pt[1], &inputItem->tri.pt[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tri2QuadGetTriangleNum(tri2QuadContext *ctx) {
|
||||||
|
return arrayGetLength(ctx->triangleArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
triangle *tri2QuadGetTriangle(tri2QuadContext *ctx, int index) {
|
||||||
|
return (triangle *)arrayGetItem(ctx->triangleArray, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tri2QuadGetQuadNum(tri2QuadContext *ctx) {
|
||||||
|
return arrayGetLength(ctx->quadArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
quad *tri2QuadGetQuad(tri2QuadContext *ctx, int index) {
|
||||||
|
return (quad *)arrayGetItem(ctx->quadArray, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tri2QuadContextDestroy(tri2QuadContext *ctx) {
|
||||||
|
arrayDestroy(ctx->inputArray);
|
||||||
|
arrayDestroy(ctx->triangleArray);
|
||||||
|
arrayDestroy(ctx->quadArray);
|
||||||
|
hashtableDestroy(ctx->edgeHashtable);
|
||||||
|
arrayDestroy(ctx->edgeArray);
|
||||||
|
free(ctx);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef TRI2QUAD_H
|
||||||
|
#define TRI2QUAD_H
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
|
typedef struct tri2QuadContext tri2QuadContext;
|
||||||
|
|
||||||
|
tri2QuadContext *tri2QuadContextCreate(void);
|
||||||
|
int tri2QuadAddTriangle(tri2QuadContext *ctx, triangle *tri);
|
||||||
|
int tri2QuadConvert(tri2QuadContext *ctx);
|
||||||
|
int tri2QuadGetTriangleNum(tri2QuadContext *ctx);
|
||||||
|
triangle *tri2QuadGetTriangle(tri2QuadContext *ctx, int index);
|
||||||
|
int tri2QuadGetQuadNum(tri2QuadContext *ctx);
|
||||||
|
quad *tri2QuadGetQuad(tri2QuadContext *ctx, int index);
|
||||||
|
void tri2QuadContextDestroy(tri2QuadContext *ctx);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -129,3 +129,12 @@ void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result) {
|
||||||
result->z = length * over->z;
|
result->z = length * over->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c) {
|
||||||
|
vec3 ab;
|
||||||
|
vec3 ac;
|
||||||
|
vec3 cross;
|
||||||
|
vec3Sub(a, b, &ab);
|
||||||
|
vec3Sub(a, c, &ac);
|
||||||
|
vec3CrossProduct(&ab, &ac, &cross);
|
||||||
|
return vec3Length(&cross) * 0.5;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal);
|
||||||
void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result);
|
void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result);
|
||||||
float vec3Angle(vec3 *a, vec3 *b);
|
float vec3Angle(vec3 *a, vec3 *b);
|
||||||
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
|
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
|
||||||
|
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue