Add triangle to quad conversion, not finish yet.

Fix convex hull algorithm.
Unify generated faces'normal.
Add hashtable.
Fix incorrect realloc in array.
master
Jeremy Hu 2016-12-28 22:16:25 +09:30
parent 97141d9ee7
commit e9e9a170e3
12 changed files with 801 additions and 127 deletions

View File

@ -15,7 +15,9 @@ SOURCES += main.cpp \
array.c \
bmesh.c \
matrix.c \
convexhull.c
convexhull.c \
tri2quad.c \
hashtable.c
HEADERS += mainwindow.h \
render.h \
@ -24,4 +26,6 @@ HEADERS += mainwindow.h \
array.h \
bmesh.h \
matrix.h \
convexhull.h
convexhull.h \
tri2quad.h \
hashtable.h

View File

@ -23,11 +23,16 @@ array *arrayCreate(int nodeSize) {
int arraySetLength(array *arr, int length) {
if (length > arr->capacity) {
int newCapacity = (arr->capacity + 1) * 2;
if (newCapacity < length) {
newCapacity = length;
}
char *newNodes = (char *)realloc(arr->nodes, arr->nodeSize * newCapacity);
if (!newNodes) {
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
return -1;
}
memset(newNodes + arr->nodeSize * arr->capacity, 0,
arr->nodeSize * (newCapacity - arr->capacity));
arr->capacity = newCapacity;
arr->nodes = newNodes;
}

View File

@ -3,10 +3,12 @@
#include <string.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include "bmesh.h"
#include "array.h"
#include "matrix.h"
#include "convexhull.h"
#include "tri2quad.h"
#include "draw.h"
#define BMESH_STEP_DISTANCE 0.4
@ -518,9 +520,12 @@ static bmeshBall *bmeshFindBallForConvexHull(bmesh *bm, bmeshBall *root,
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;
quad q;
int vertexIndex[4];
int needUpdateOutmost = 0;
vec3Scale(&ballForConvexHull->localYaxis, ballForConvexHull->radius, &y);
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(&q.pt[3], &z, &q.pt[3]);
convexHullAddVertex(hull, &q.pt[0], ballForConvexHull->index, 0);
convexHullAddVertex(hull, &q.pt[1], ballForConvexHull->index, 1);
convexHullAddVertex(hull, &q.pt[2], ballForConvexHull->index, 2);
convexHullAddVertex(hull, &q.pt[3], ballForConvexHull->index, 3);
vertexIndex[0] = convexHullAddVertex(hull, &q.pt[0], ballForConvexHull->index, 0);
vertexIndex[1] = convexHullAddVertex(hull, &q.pt[1], ballForConvexHull->index, 1);
vertexIndex[2] = convexHullAddVertex(hull, &q.pt[2], ballForConvexHull->index, 2);
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) {
@ -548,12 +565,22 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
return 0;
}
ball->roundColor = bm->roundColor;
if (BMESH_BALL_TYPE_ROOT == ball->type) {
convexHull *hull = convexHullCreate();
if (BMESH_BALL_TYPE_ROOT == ball->type && 4 == ball->index) {
tri2QuadContext *t2q;
convexHull *hull;
bmeshBall *outmostBall = 0;
int outmostBallFirstVertexIndex = 0;
hull = convexHullCreate();
if (!hull) {
fprintf(stderr, "%s:convexHullCreate failed.\n", __FUNCTION__);
return -1;
}
t2q = tri2QuadContextCreate();
if (!t2q) {
fprintf(stderr, "%s:tri2QuadContextCreate failed.\n", __FUNCTION__);
convexHullDestroy(hull);
return -1;
}
glColor3f(0.0, 0.0, 0.0);
drawDebugPrintf("root <%f,%f,%f>", ball->position.x,
ball->position.y, ball->position.z);
@ -561,19 +588,40 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
child;
child = bmeshGetBallNextChild(bm, ball, &iterator)) {
ballForConvexHull = bmeshFindBallForConvexHull(bm, ball, child);
addBallToHull(hull, ballForConvexHull);
addBallToHull(hull, ballForConvexHull,
&outmostBall, &outmostBallFirstVertexIndex);
}
if (parent) {
addBallToHull(hull, parent);
addBallToHull(hull, parent, &outmostBall, &outmostBallFirstVertexIndex);
}
if (outmostBall) {
convexHullAddTodo(hull, outmostBallFirstVertexIndex + 0,
outmostBallFirstVertexIndex + 1, outmostBallFirstVertexIndex + 2);
}
convexHullGenerate(hull);
glPushMatrix();
convexHullUnifyNormals(hull, &ball->position);
{
int triIndex;
glColor3f(1.0f, 1.0f, 1.0f);
for (triIndex = 0; triIndex < convexHullGetTriangleNum(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);
}
}
@ -593,8 +641,68 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
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();
convexHullDestroy(hull);
tri2QuadContextDestroy(t2q);
}
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;

View File

@ -3,14 +3,14 @@
#include <string.h>
#include "convexhull.h"
#include "array.h"
#include "hashtable.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
//
//
// 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 {
vec3 pt;
@ -18,18 +18,50 @@ typedef struct {
int orderOnPlane;
} converHullVertex;
typedef struct face {
int indices[3];
} face;
struct convexHull {
array *vertexArray;
array *openEdgeArray;
array *triangleArray;
int nextEdgeIndex;
array *todoArray;
array *faceArray;
int nextTodoIndex;
unsigned int *openEdgeExistMap;
hashtable *faceHashtable;
face findFace;
triangle returnTriangle;
};
typedef struct {
int firstVertex;
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 *hull = (convexHull *)calloc(1, sizeof(convexHull));
@ -40,16 +72,26 @@ convexHull *convexHullCreate(void) {
hull->vertexArray = arrayCreate(sizeof(converHullVertex));
if (!hull->vertexArray) {
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
convexHullDestroy(hull);
return 0;
}
hull->openEdgeArray = arrayCreate(sizeof(edge));
if (!hull->openEdgeArray) {
hull->todoArray = arrayCreate(sizeof(todo));
if (!hull->todoArray) {
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
convexHullDestroy(hull);
return 0;
}
hull->triangleArray = arrayCreate(sizeof(triangle));
if (!hull->triangleArray) {
hull->faceArray = arrayCreate(sizeof(face));
if (!hull->faceArray) {
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 hull;
@ -65,11 +107,14 @@ void convexHullMarkEdgeAsExsits(convexHull *hull, int firstVertex,
int convexHullEdgeExsits(convexHull *hull, int firstVertex,
int secondVertex) {
if (hull->openEdgeExistMap) {
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
return hull->openEdgeExistMap[unitIndex] & (0x00000001 << unitOffset);
}
return 0;
}
int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
int orderOnPlane) {
@ -86,31 +131,24 @@ int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
return newVertex;
}
int convexHullAddOpenEdgeNoCheck(convexHull *hull, int firstVertex,
int secondVertex) {
edge *e;
int newEdge = arrayGetLength(hull->openEdgeArray);
int convexHullAddTodoNoCheck(convexHull *hull, int firstVertex,
int secondVertex, int thirdVertex) {
todo *t;
int newEdge = arrayGetLength(hull->todoArray);
if (firstVertex < 0 || secondVertex < 0) {
fprintf(stderr, "%s:Invalid params(firstVertex:%d secondVertex:%d).\n",
__FUNCTION__, firstVertex, secondVertex);
return -1;
}
if (0 != arraySetLength(hull->openEdgeArray, newEdge + 1)) {
if (0 != arraySetLength(hull->todoArray, newEdge + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1;
}
e = (edge *)arrayGetItem(hull->openEdgeArray, newEdge);
memset(e, 0, sizeof(edge));
e->firstVertex = firstVertex;
e->secondVertex = secondVertex;
return 0;
}
int convexHullAddEdge(convexHull *hull, int p1, int p2) {
convexHullMarkEdgeAsExsits(hull, p1, p2);
if (!convexHullEdgeExsits(hull, p2, p1)) {
return convexHullAddOpenEdgeNoCheck(hull, p2, p1);
}
t = (todo *)arrayGetItem(hull->todoArray, newEdge);
memset(t, 0, sizeof(todo));
t->firstVertex = firstVertex;
t->secondVertex = secondVertex;
t->thirdVertex = thirdVertex;
return 0;
}
@ -119,9 +157,15 @@ static int isInAdjacentOrder(int order1, int order2) {
(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) {
triangle *tri;
face *tri;
converHullVertex *vtx1;
converHullVertex *vtx2;
converHullVertex *vtx3;
@ -147,16 +191,26 @@ int convexHullAddTriangle(convexHull *hull, int firstVertex, int secondVertex,
return 0;
}
}
newTri = arrayGetLength(hull->triangleArray);
if (0 != arraySetLength(hull->triangleArray, newTri + 1)) {
memset(&hull->findFace, 0, sizeof(hull->findFace));
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__);
return -1;
}
tri = (triangle *)arrayGetItem(hull->triangleArray, newTri);
memset(tri, 0, sizeof(triangle));
tri->pt[0] = vtx1->pt;
tri->pt[1] = vtx2->pt;
tri->pt[2] = vtx3->pt;
tri = (face *)arrayGetItem(hull->faceArray, newTri);
*tri = hull->findFace;
if (0 != hashtableInsert(hull->faceHashtable,
(char *)0 + newTri + 1)) {
fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__);
return -1;
}
}
return 0;
}
@ -167,8 +221,9 @@ static void convexHullReleaseForGenerate(convexHull *hull) {
void convexHullDestroy(convexHull *hull) {
arrayDestroy(hull->vertexArray);
arrayDestroy(hull->openEdgeArray);
arrayDestroy(hull->triangleArray);
arrayDestroy(hull->todoArray);
arrayDestroy(hull->faceArray);
hashtableDestroy(hull->faceHashtable);
convexHullReleaseForGenerate(hull);
free(hull);
}
@ -183,62 +238,47 @@ static int convexHullPrepareForGenerate(convexHull *hull) {
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
return -1;
}
hull->nextEdgeIndex = 0;
hull->nextTodoIndex = 0;
return 0;
}
int convexHullGetLower(convexHull *hull) {
int index = 0;
int convexHullGetNextVertex(convexHull *hull, int p1Index, int p2Index,
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;
for (i = 1; i < arrayGetLength(hull->vertexArray); ++i) {
vec3 *pI = (vec3 *)arrayGetItem(hull->vertexArray, i);
vec3 *pIndex = (vec3 *)arrayGetItem(hull->vertexArray, index);
if (pI->z < pIndex->z) {
index = i;
} else if (pI->z == pIndex->z) {
if (pI->y < pIndex->y) {
index = i;
} else if (pI->x < pIndex->x) {
index = i;
float angle;
float maxAngle = 0;
int candidateIndex = -1;
vec3Normal(p1, p2, p3, &beginNormal);
for (i = 0; i < arrayGetLength(hull->vertexArray); ++i) {
if (i != p1Index && i != p2Index && i != p3Index) {
vec3Normal(p1, p2, (vec3 *)arrayGetItem(hull->vertexArray, i),
&endNormal);
angle = vec3Angle(&beginNormal, &endNormal);
if (angle > maxAngle) {
candidateIndex = i;
maxAngle = angle;
}
}
}
return index;
}
int convexHullGetNextVertex(convexHull *hull, int p1Index, int p2Index) {
vec3 pCorner = {1, 1, 0};
vec3 *p1 = (vec3 *)arrayGetItem(hull->vertexArray, p1Index);
vec3 *p2 = p2Index < 0 ? &pCorner : (vec3 *)arrayGetItem(hull->vertexArray,
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 candidateIndex;
}
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2,
int vertex3) {
if (!convexHullEdgeExsits(hull, vertex1, vertex2)) {
return convexHullAddTodoNoCheck(hull, vertex1, vertex2, vertex3);
}
return 0;
}
int convexHullGenerate(convexHull *hull) {
int index1, index2, index3;
convexHullReleaseForGenerate(hull);
@ -246,34 +286,63 @@ int convexHullGenerate(convexHull *hull) {
fprintf(stderr, "%s:convexHullPrepareForGenerate failed.\n", __FUNCTION__);
return -1;
}
index1 = convexHullGetLower(hull);
index2 = convexHullGetNextVertex(hull, index1, -1);
convexHullAddEdge(hull, index2, index1);
//glColor3f(0.0, 0.0, 0.0);
//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;
while (hull->nextTodoIndex < arrayGetLength(hull->todoArray)) {
todo *t = (todo *)arrayGetItem(hull->todoArray, hull->nextTodoIndex++);
index1 = t->firstVertex;
index2 = t->secondVertex;
if (convexHullEdgeExsits(hull, index1, index2)) {
continue;
}
convexHullMarkEdgeAsExsits(hull, index1, index2);
index3 = convexHullGetNextVertex(hull, index1, index2);
//drawDebugPrintf("%d,%d,%d", index1, index2, index3);
convexHullAddTriangle(hull, index1, index2, index3);
convexHullAddEdge(hull, index1, index2);
convexHullAddEdge(hull, index2, index3);
convexHullAddEdge(hull, index3, index1);
index3 = convexHullGetNextVertex(hull, index1, index2, t->thirdVertex);
if (-1 == index3) {
continue;
}
convexHullAddFace(hull, index1, index2, index3);
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;
}
int convexHullGetTriangleNum(convexHull *hull) {
return arrayGetLength(hull->triangleArray);
return arrayGetLength(hull->faceArray);
}
triangle *convexHullGetTriangle(convexHull *hull, int index) {
triangle *tri = (triangle *)arrayGetItem(hull->triangleArray, index);
return tri;
int i;
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;
}

View File

@ -9,7 +9,9 @@ int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
int orderOnPlane);
void convexHullDestroy(convexHull *hull);
int convexHullGenerate(convexHull *hull);
int convexHullUnifyNormals(convexHull *hull, vec3 *origin);
int convexHullGetTriangleNum(convexHull *hull);
triangle *convexHullGetTriangle(convexHull *hull, int index);
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2, int vertex3);
#endif

117
src/hashtable.c Normal file
View File

@ -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);
}

15
src/hashtable.h Normal file
View File

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

View File

@ -8,10 +8,10 @@
#include "matrix.h"
#include "vector3d.h"
static const float bmeshBallColors[][3] {
{0, 0.78, 1},
{1, 0, 0},
{1, 1, 1}
static const float bmeshBallColors[][4] {
{0.00, 0.78, 1.00, 0.5},
{1.00, 0.00, 0.00, 0.5},
{1.00, 1.00, 1.00, 0.5}
};
static const float bmeshBoneColor[3] = {1, 1, 0};
@ -27,11 +27,14 @@ int drawDebugPrintf(const char *fmt, ...) {
va_start(args, fmt);
vsnprintf(text, sizeof(text), fmt, args);
debugOutputTop += 9;
if (debugOutputTop > 200) {
debugOutputTop = 0;
}
return drawText(x, y, text);
}
static int drawBmeshBall(bmesh *bm, bmeshBall *ball) {
glColor3fv(bmeshBallColors[ball->type]);
glColor4fv(bmeshBallColors[ball->type]);
drawSphere(&ball->position, ball->radius, 36, 24);
return 0;
}
@ -129,7 +132,7 @@ static void drawBmeshBallQuadRecursively(bmesh *bm, bmeshBall *ball) {
glPopMatrix();
*/
drawBmeshBallQuad(ball);
//drawBmeshBallQuad(ball);
for (child = bmeshGetBallFirstChild(bm, ball, &iterator);
child;
@ -277,7 +280,7 @@ void Render::paintGL() {
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
bmeshBone *bone = bmeshGetBone(bm, index);
drawBmeshBone(bm, bone);
//drawBmeshBone(bm, bone);
}
/*
glColor4f(1.0f, 1.0f, 1.0f, 0.5);

324
src/tri2quad.c Normal file
View File

@ -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);
}

17
src/tri2quad.h Normal file
View File

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

View File

@ -129,3 +129,12 @@ void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result) {
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;
}

View File

@ -25,6 +25,7 @@ void vec3Normal(vec3 *a, vec3 *b, vec3 *c, vec3 *normal);
void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result);
float vec3Angle(vec3 *a, vec3 *b);
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c);
#ifdef __cplusplus
}