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 \
|
||||
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
|
|
@ -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;
|
||||
}
|
||||
|
|
130
src/bmesh.c
130
src/bmesh.c
|
@ -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;
|
||||
|
|
283
src/convexhull.c
283
src/convexhull.c
|
@ -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,10 +107,13 @@ void convexHullMarkEdgeAsExsits(convexHull *hull, int firstVertex,
|
|||
|
||||
int convexHullEdgeExsits(convexHull *hull, int firstVertex,
|
||||
int secondVertex) {
|
||||
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);
|
||||
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,
|
||||
|
@ -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)) {
|
||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||
return -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 = (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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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,60 +238,45 @@ 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;
|
||||
|
||||
return candidateIndex;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2,
|
||||
int vertex3) {
|
||||
if (!convexHullEdgeExsits(hull, vertex1, vertex2)) {
|
||||
return convexHullAddTodoNoCheck(hull, vertex1, vertex2, vertex3);
|
||||
}
|
||||
return candidateIndex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int convexHullGenerate(convexHull *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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
float vec3Angle(vec3 *a, vec3 *b);
|
||||
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
|
||||
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue