Add Catmull-Clark subdivision algorithm.
parent
21e46e5e16
commit
32057f4e4d
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
|
@ -0,0 +1,750 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "subdivide.h"
|
||||
#include "draw.h"
|
||||
|
||||
//
|
||||
// Catmull Clark Subdivision
|
||||
// Modified from https://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface/C
|
||||
//
|
||||
|
||||
typedef struct subdivLink {
|
||||
int index;
|
||||
int nextLink;
|
||||
} subdivLink;
|
||||
|
||||
typedef struct subdivVertex {
|
||||
vec3 v;
|
||||
vec3 avgNorm;
|
||||
int index;
|
||||
int newVertexIndex;
|
||||
int edgeLink;
|
||||
int edgeNum;
|
||||
int faceLink;
|
||||
int faceNum;
|
||||
int indexOnNewModel;
|
||||
} subdivVertex;
|
||||
|
||||
typedef struct subdivEdge {
|
||||
int index;
|
||||
int faceLink;
|
||||
int faceNum;
|
||||
int v[2];
|
||||
int edgePt;
|
||||
vec3 avg;
|
||||
} subdivEdge;
|
||||
|
||||
typedef struct subdivFace {
|
||||
int index;
|
||||
int edgeLink;
|
||||
int edgeNum;
|
||||
int vertexLink;
|
||||
int vertexNum;
|
||||
vec3 norm;
|
||||
int avg;
|
||||
} subdivFace;
|
||||
|
||||
struct subdivModel {
|
||||
array *vertexArray;
|
||||
array *faceArray;
|
||||
array *edgeArray;
|
||||
array *indexArray;
|
||||
int faceLink;
|
||||
int faceNum;
|
||||
int edgeLink;
|
||||
int edgeNum;
|
||||
int vertexLink;
|
||||
int vertexNum;
|
||||
};
|
||||
|
||||
static void initVertex(subdivVertex *v) {
|
||||
memset(v, 0, sizeof(subdivVertex));
|
||||
v->newVertexIndex = -1;
|
||||
v->edgeLink = -1;
|
||||
v->faceLink = -1;
|
||||
v->indexOnNewModel = -1;
|
||||
};
|
||||
|
||||
static void initEdge(subdivEdge *e) {
|
||||
memset(e, 0, sizeof(subdivEdge));
|
||||
e->faceLink = -1;
|
||||
e->v[0] = -1;
|
||||
e->v[0] = -1;
|
||||
e->edgePt = -1;
|
||||
}
|
||||
|
||||
static void initFace(subdivFace *f) {
|
||||
memset(f, 0, sizeof(subdivFace));
|
||||
f->edgeLink = -1;
|
||||
f->vertexLink = -1;
|
||||
f->avg = -1;
|
||||
}
|
||||
|
||||
subdivModel *subdivCreateModel(void) {
|
||||
subdivModel *model = (subdivModel *)calloc(1, sizeof(subdivModel));
|
||||
if (!model) {
|
||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
model->faceLink = -1;
|
||||
model->edgeLink = -1;
|
||||
model->vertexLink = -1;
|
||||
model->vertexArray = arrayCreate(sizeof(subdivVertex));
|
||||
if (!model->vertexArray) {
|
||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
model->faceArray = arrayCreate(sizeof(subdivFace));
|
||||
if (!model->faceArray) {
|
||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
model->edgeArray = arrayCreate(sizeof(subdivEdge));
|
||||
if (!model->edgeArray) {
|
||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
model->indexArray = arrayCreate(sizeof(subdivLink));
|
||||
if (!model->indexArray) {
|
||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
void subdivDestroyModel(subdivModel *model) {
|
||||
arrayDestroy(model->vertexArray);
|
||||
arrayDestroy(model->faceArray);
|
||||
arrayDestroy(model->edgeArray);
|
||||
arrayDestroy(model->indexArray);
|
||||
free(model);
|
||||
}
|
||||
|
||||
static int allocLink(subdivModel *model, int index) {
|
||||
subdivLink *linkItem;
|
||||
int newLink = arrayGetLength(model->indexArray);
|
||||
if (0 != arraySetLength(model->indexArray, newLink + 1)) {
|
||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, newLink);
|
||||
linkItem->index = index;
|
||||
linkItem->nextLink = -1;
|
||||
return newLink;
|
||||
}
|
||||
|
||||
static int subdivLinkElement(subdivModel *model, int current, int order) {
|
||||
int i, iterator;
|
||||
int element = -1;
|
||||
subdivLink *linkItem;
|
||||
iterator = current;
|
||||
for (i = 0; i <= order && -1 != iterator; ++i) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
element = linkItem->index;
|
||||
iterator = linkItem->nextLink;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
static int pushLink(subdivModel *model, int *link, int *num, int index) {
|
||||
int newLink = allocLink(model, index);
|
||||
int i, iterator;
|
||||
subdivLink *linkItem = 0;
|
||||
if (-1 == newLink) {
|
||||
fprintf(stderr, "%s:allocLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (-1 != *link) {
|
||||
iterator = *link;
|
||||
for (i = 0; i < *num; ++i) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
iterator = linkItem->nextLink;
|
||||
}
|
||||
linkItem->nextLink = newLink;
|
||||
} else {
|
||||
*link = newLink;
|
||||
}
|
||||
(*num)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static subdivVertex *allocVertex(subdivModel *model) {
|
||||
subdivVertex *vertex;
|
||||
int newVertexIndex = arrayGetLength(model->vertexArray);
|
||||
if (0 != arraySetLength(model->vertexArray, newVertexIndex + 1)) {
|
||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
vertex = arrayGetItem(model->vertexArray, newVertexIndex);
|
||||
initVertex(vertex);
|
||||
vertex->index = newVertexIndex;
|
||||
if (0 != pushLink(model, &model->vertexLink, &model->vertexNum,
|
||||
vertex->index)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return vertex;
|
||||
}
|
||||
|
||||
static subdivEdge *allocEdge(subdivModel *model) {
|
||||
subdivEdge *edge;
|
||||
int newEdgeIndex = arrayGetLength(model->edgeArray);
|
||||
if (0 != arraySetLength(model->edgeArray, newEdgeIndex + 1)) {
|
||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
edge = arrayGetItem(model->edgeArray, newEdgeIndex);
|
||||
initEdge(edge);
|
||||
edge->index = newEdgeIndex;
|
||||
return edge;
|
||||
}
|
||||
|
||||
static subdivFace *allocFace(subdivModel *model) {
|
||||
subdivFace *face;
|
||||
int newFaceIndex = arrayGetLength(model->faceArray);
|
||||
if (0 != arraySetLength(model->faceArray, newFaceIndex + 1)) {
|
||||
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
face = arrayGetItem(model->faceArray, newFaceIndex);
|
||||
initFace(face);
|
||||
face->index = newFaceIndex;
|
||||
return face;
|
||||
}
|
||||
|
||||
static subdivVertex *getVertex(subdivModel *model, int index) {
|
||||
if (-1 == index) {
|
||||
return 0;
|
||||
}
|
||||
return (subdivVertex *)arrayGetItem(model->vertexArray, index);
|
||||
}
|
||||
|
||||
static subdivEdge *getEdge(subdivModel *model, int index) {
|
||||
if (-1 == index) {
|
||||
return 0;
|
||||
}
|
||||
return (subdivEdge *)arrayGetItem(model->edgeArray, index);
|
||||
}
|
||||
|
||||
static subdivFace *getFace(subdivModel *model, int index) {
|
||||
if (-1 == index) {
|
||||
return 0;
|
||||
}
|
||||
return (subdivFace *)arrayGetItem(model->faceArray, index);
|
||||
}
|
||||
|
||||
static int isHoleEdge(subdivModel *model, int e) {
|
||||
return 1 == getEdge(model, e)->faceNum;
|
||||
}
|
||||
|
||||
static int isHoleVertex(subdivModel *model, int p) {
|
||||
return getVertex(model, p)->faceNum != getVertex(model, p)->edgeNum;
|
||||
}
|
||||
|
||||
static int facePoint(subdivModel *model, int f);
|
||||
|
||||
static int edgePoint(subdivModel *model, int e) {
|
||||
int nv = getEdge(model, e)->edgePt;
|
||||
if (-1 == nv) {
|
||||
subdivVertex *newVertex = allocVertex(model);
|
||||
if (!newVertex) {
|
||||
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
nv = newVertex->index;
|
||||
getEdge(model, e)->edgePt = nv;
|
||||
getEdge(model, e)->avg = getVertex(model, getEdge(model, e)->v[0])->v;
|
||||
vec3Add(&getEdge(model, e)->avg,
|
||||
&getVertex(model, getEdge(model, e)->v[1])->v, &getEdge(model, e)->avg);
|
||||
getVertex(model, nv)->v = getEdge(model, e)->avg;
|
||||
if (!isHoleEdge(model, e)) {
|
||||
int iterator;
|
||||
iterator = getEdge(model, e)->faceLink;
|
||||
while (-1 != iterator) {
|
||||
int f;
|
||||
int fp;
|
||||
subdivLink *linkItem = (subdivLink *)arrayGetItem(model->indexArray,
|
||||
iterator);
|
||||
f = linkItem->index;
|
||||
iterator = linkItem->nextLink;
|
||||
fp = facePoint(model, f);
|
||||
if (-1 == fp) {
|
||||
fprintf(stderr, "%s:facePoint failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
vec3Add(&getVertex(model, nv)->v, &getVertex(model, fp)->v,
|
||||
&getVertex(model, nv)->v);
|
||||
}
|
||||
vec3Scale(&getVertex(model, nv)->v, 1.0 / 4, &getVertex(model, nv)->v);
|
||||
} else {
|
||||
vec3Scale(&getVertex(model, nv)->v, 1.0 / 2, &getVertex(model, nv)->v);
|
||||
}
|
||||
vec3Scale(&getEdge(model, e)->avg, 1.0 / 2, &getEdge(model, e)->avg);
|
||||
}
|
||||
return nv;
|
||||
}
|
||||
|
||||
static int facePoint(subdivModel *model, int f) {
|
||||
int nv = getFace(model, f)->avg;
|
||||
if (-1 == nv) {
|
||||
int iterator;
|
||||
subdivVertex *newVertex = allocVertex(model);
|
||||
if (!newVertex) {
|
||||
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
nv = newVertex->index;
|
||||
getFace(model, f)->avg = nv;
|
||||
iterator = getFace(model, f)->vertexLink;
|
||||
while (-1 != iterator) {
|
||||
int p;
|
||||
subdivLink *linkItem = (subdivLink *)arrayGetItem(model->indexArray,
|
||||
iterator);
|
||||
p = linkItem->index;
|
||||
iterator = linkItem->nextLink;
|
||||
if (getFace(model, f)->vertexLink == iterator) {
|
||||
getVertex(model, nv)->v = getVertex(model, p)->v;
|
||||
} else {
|
||||
vec3Add(&getVertex(model, nv)->v, &getVertex(model, p)->v,
|
||||
&getVertex(model, nv)->v);
|
||||
}
|
||||
}
|
||||
vec3Scale(&getVertex(model, nv)->v, 1.0 / (getFace(model, f)->vertexNum),
|
||||
&getVertex(model, nv)->v);
|
||||
}
|
||||
return nv;
|
||||
}
|
||||
|
||||
static void scaleAdd(vec3 *a, vec3 *b, float scale, vec3 *result) {
|
||||
vec3 tmp;
|
||||
vec3Scale(b, scale, &tmp);
|
||||
vec3Add(a, &tmp, result);
|
||||
}
|
||||
|
||||
static int updatedPoint(subdivModel *model, int p) {
|
||||
int n = 0;
|
||||
int iterator;
|
||||
subdivVertex *newVertex;
|
||||
int facePt;
|
||||
int e;
|
||||
subdivFace *f;
|
||||
subdivLink *link;
|
||||
int nv;
|
||||
int ep;
|
||||
vec3 sum = {0, 0, 0};
|
||||
|
||||
nv = getVertex(model, p)->newVertexIndex;
|
||||
if (-1 != nv) {
|
||||
return nv;
|
||||
}
|
||||
|
||||
newVertex = allocVertex(model);
|
||||
if (!newVertex) {
|
||||
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
nv = newVertex->index;
|
||||
getVertex(model, p)->newVertexIndex = nv;
|
||||
if (isHoleVertex(model, p)) {
|
||||
getVertex(model, nv)->v = getVertex(model, p)->v;
|
||||
iterator = getVertex(model, p)->edgeLink;
|
||||
while (-1 != iterator) {
|
||||
link = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
e = link->index;
|
||||
iterator = link->nextLink;
|
||||
if (!isHoleEdge(model, e)) {
|
||||
continue;
|
||||
}
|
||||
ep = edgePoint(model, e);
|
||||
if (-1 == ep) {
|
||||
fprintf(stderr, "%s:edgePoint failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
vec3Add(&getVertex(model, nv)->v, &getVertex(model, ep)->v,
|
||||
&getVertex(model, nv)->v);
|
||||
n++;
|
||||
}
|
||||
vec3Scale(&getVertex(model, nv)->v, 1.0 / (n + 1),
|
||||
&getVertex(model, nv)->v);
|
||||
} else {
|
||||
n = getVertex(model, p)->faceNum;
|
||||
iterator = getVertex(model, p)->faceLink;
|
||||
while (-1 != iterator) {
|
||||
link = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
f = link->index;
|
||||
iterator = link->nextLink;
|
||||
facePt = facePoint(model, f);
|
||||
if (-1 == facePt) {
|
||||
fprintf(stderr, "%s:facePoint failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
vec3Add(&sum, &getVertex(model, facePt)->v, &sum);
|
||||
}
|
||||
iterator = getVertex(model, p)->edgeLink;
|
||||
while (-1 != iterator) {
|
||||
link = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
e = link->index;
|
||||
iterator = link->nextLink;
|
||||
ep = edgePoint(model, e);
|
||||
if (-1 == ep) {
|
||||
fprintf(stderr, "%s:edgePoint failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
scaleAdd(&sum, &getVertex(model, ep)->v, 2, &sum);
|
||||
}
|
||||
vec3Scale(&sum, 1.0 / n, &sum);
|
||||
scaleAdd(&sum, &getVertex(model, p)->v, n - 3, &sum);
|
||||
vec3Scale(&sum, 1.0 / n, &sum);
|
||||
getVertex(model, nv)->v = sum;
|
||||
}
|
||||
|
||||
return nv;
|
||||
}
|
||||
|
||||
static int subdivCalculteNorms(subdivModel *model) {
|
||||
int i, j, n;
|
||||
int faceIterator;
|
||||
int nextFaceIterator;
|
||||
int vertexIterator;
|
||||
int nextVertexIterator;
|
||||
subdivFace *f;
|
||||
subdivLink *linkItem;
|
||||
subdivVertex *v;
|
||||
subdivVertex *v0;
|
||||
subdivVertex *v1;
|
||||
vec3 d1, d2, norm;
|
||||
|
||||
faceIterator = model->faceLink;
|
||||
j = 0;
|
||||
while (-1 != faceIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, faceIterator);
|
||||
f = getFace(model, linkItem->index);
|
||||
nextFaceIterator = linkItem->nextLink;
|
||||
vertexIterator = f->vertexLink;
|
||||
n = f->vertexNum;
|
||||
i = 0;
|
||||
while (-1 != vertexIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, faceIterator);
|
||||
f = getFace(model, linkItem->index);
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, vertexIterator);
|
||||
v = getVertex(model, linkItem->index);
|
||||
vertexIterator = linkItem->nextLink;
|
||||
v0 = getVertex(model,
|
||||
subdivLinkElement(model, f->vertexLink, i ? i - 1 : n - 1));
|
||||
v1 = getVertex(model,
|
||||
subdivLinkElement(model, f->vertexLink, (i + 1) % n));
|
||||
vec3Sub(&v->v, &v0->v, &d1);
|
||||
vec3Sub(&v1->v, &v->v, &d2);
|
||||
vec3CrossProduct(&d1, &d2, &norm);
|
||||
vec3Add(&f->norm, &norm, &f->norm);
|
||||
++i;
|
||||
}
|
||||
if (i > 1) {
|
||||
vec3Normalize(&f->norm);
|
||||
}
|
||||
faceIterator = nextFaceIterator;
|
||||
++j;
|
||||
}
|
||||
|
||||
vertexIterator = model->vertexLink;
|
||||
while (-1 != vertexIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, vertexIterator);
|
||||
v = getVertex(model, linkItem->index);
|
||||
nextVertexIterator = linkItem->nextLink;
|
||||
faceIterator = v->faceLink;
|
||||
j = 0;
|
||||
while (-1 != faceIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, faceIterator);
|
||||
f = getFace(model, linkItem->index);
|
||||
faceIterator = linkItem->nextLink;
|
||||
vec3Add(&v->avgNorm, &f->norm, &v->avgNorm);
|
||||
++j;
|
||||
}
|
||||
if (j > 1) {
|
||||
vec3Normalize(&v->avgNorm);
|
||||
}
|
||||
vertexIterator = nextVertexIterator;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drawModel(subdivModel *model) {
|
||||
subdivLink *linkItem;
|
||||
subdivFace *f;
|
||||
subdivVertex *v;
|
||||
int faceIterator;
|
||||
int vertexIterator;
|
||||
faceIterator = model->faceLink;
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
while (-1 != faceIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, faceIterator);
|
||||
f = getFace(model, linkItem->index);
|
||||
faceIterator = linkItem->nextLink;
|
||||
vertexIterator = f->vertexLink;
|
||||
glBegin(GL_POLYGON);
|
||||
while (-1 != vertexIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, vertexIterator);
|
||||
v = getVertex(model, linkItem->index);
|
||||
vertexIterator = linkItem->nextLink;
|
||||
glNormal3fv(&(f->norm.x));
|
||||
glVertex3fv(&(v->v.x));
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
subdivModel *subdivCatmullClark(subdivModel *model) {
|
||||
int j, ai, bi, ci, di;
|
||||
int a, b, c, d;
|
||||
int faceIterator;
|
||||
int nextFaceIterator;
|
||||
int vertexIterator;
|
||||
int f;
|
||||
subdivLink *linkItem;
|
||||
int p;
|
||||
subdivModel *outputModel;
|
||||
|
||||
outputModel = subdivCreateModel();
|
||||
if (!outputModel) {
|
||||
fprintf(stderr, "%s:subdivCreateModel failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
faceIterator = model->faceLink;
|
||||
while (-1 != faceIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, faceIterator);
|
||||
f = linkItem->index;
|
||||
j = 0;
|
||||
nextFaceIterator = linkItem->nextLink;
|
||||
vertexIterator = getFace(model, f)->vertexLink;
|
||||
while (-1 != vertexIterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, vertexIterator);
|
||||
p = linkItem->index;
|
||||
vertexIterator = linkItem->nextLink;
|
||||
ai = updatedPoint(model, p);
|
||||
if (-1 == ai) {
|
||||
fprintf(stderr, "%s:updatedPoint failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
bi = edgePoint(model, subdivLinkElement(model,
|
||||
getFace(model, f)->edgeLink, (j + 1) % getFace(model, f)->edgeNum));
|
||||
if (-1 == bi) {
|
||||
fprintf(stderr, "%s:edgePoint failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
ci = facePoint(model, f);
|
||||
if (-1 == ci) {
|
||||
fprintf(stderr, "%s:facePoint failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
di = edgePoint(model, subdivLinkElement(model,
|
||||
getFace(model, f)->edgeLink, j));
|
||||
if (-1 == di) {
|
||||
fprintf(stderr, "%s:edgePoint failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
a = getVertex(model, ai)->indexOnNewModel;
|
||||
if (-1 == a) {
|
||||
a = subdivAddVertex(outputModel, &getVertex(model, ai)->v);
|
||||
getVertex(model, ai)->indexOnNewModel = a;
|
||||
}
|
||||
b = getVertex(model, bi)->indexOnNewModel;
|
||||
if (-1 == b) {
|
||||
b = subdivAddVertex(outputModel, &getVertex(model, bi)->v);
|
||||
getVertex(model, bi)->indexOnNewModel = b;
|
||||
}
|
||||
c = getVertex(model, ci)->indexOnNewModel;
|
||||
if (-1 == c) {
|
||||
c = subdivAddVertex(outputModel, &getVertex(model, ci)->v);
|
||||
getVertex(model, ci)->indexOnNewModel = c;
|
||||
}
|
||||
d = getVertex(model, di)->indexOnNewModel;
|
||||
if (-1 == d) {
|
||||
d = subdivAddVertex(outputModel, &getVertex(model, di)->v);
|
||||
getVertex(model, di)->indexOnNewModel = d;
|
||||
}
|
||||
if (-1 == a || -1 == b || -1 == c || -1 == d) {
|
||||
fprintf(stderr, "%s:subdivAddVertex failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
if (-1 == subdivAddQuadFace(outputModel, a, b, c, d)) {
|
||||
fprintf(stderr, "%s:subdivAddFace failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
faceIterator = nextFaceIterator;
|
||||
}
|
||||
|
||||
if (0 != subdivCalculteNorms(outputModel)) {
|
||||
fprintf(stderr, "%s:subdivCalculteNorms failed.\n", __FUNCTION__);
|
||||
subdivDestroyModel(outputModel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return outputModel;
|
||||
}
|
||||
|
||||
int subdivAddVertex(subdivModel *model, vec3 *v) {
|
||||
subdivVertex *newVertex = allocVertex(model);
|
||||
if (!newVertex) {
|
||||
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
newVertex->v = *v;
|
||||
return newVertex->index;
|
||||
}
|
||||
|
||||
static int subdivAddEdge(subdivModel *model, int p1, int p2) {
|
||||
subdivEdge *newEdge = allocEdge(model);
|
||||
subdivVertex *v1;
|
||||
subdivVertex *v2;
|
||||
if (!newEdge) {
|
||||
fprintf(stderr, "%s:allocEdge failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
newEdge->v[0] = p1;
|
||||
newEdge->v[1] = p2;
|
||||
v1 = getVertex(model, p1);
|
||||
v2 = getVertex(model, p2);
|
||||
if (-1 == pushLink(model, &v1->edgeLink, &v1->edgeNum, newEdge->index)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (-1 == pushLink(model, &v2->edgeLink, &v2->edgeNum, newEdge->index)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (-1 == pushLink(model, &model->edgeLink, &model->edgeNum, newEdge->index)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return newEdge->index;
|
||||
}
|
||||
|
||||
static int subdivEdgeByVertexs(subdivModel *model, int p1, int p2) {
|
||||
subdivLink *linkItem;
|
||||
subdivEdge *e;
|
||||
subdivVertex *v1 = getVertex(model, p1);
|
||||
int newEdgeIndex;
|
||||
int iterator = v1->edgeLink;
|
||||
while (-1 != iterator) {
|
||||
linkItem = (subdivLink *)arrayGetItem(model->indexArray, iterator);
|
||||
e = getEdge(model, linkItem->index);
|
||||
iterator = linkItem->nextLink;
|
||||
if (e->v[0] == p2 || e->v[1] == p2) {
|
||||
return e->index;
|
||||
}
|
||||
}
|
||||
newEdgeIndex = subdivAddEdge(model, p1, p2);
|
||||
return newEdgeIndex;
|
||||
}
|
||||
|
||||
static int subdivAddFace(subdivModel *model, int *vertexs, int vertexNum) {
|
||||
int i;
|
||||
subdivFace *f = allocFace(model);
|
||||
int p0, p1;
|
||||
int newFaceIndex;
|
||||
int edgeIndex;
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s:allocFace failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
newFaceIndex = f->index;
|
||||
if (0 != pushLink(model, &model->faceLink, &model->faceNum, newFaceIndex)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
p0 = vertexs[0];
|
||||
for (i = 1; i <= vertexNum; ++i, p0 = p1) {
|
||||
subdivVertex *v1;
|
||||
subdivEdge *e;
|
||||
p1 = vertexs[i % vertexNum];
|
||||
v1 = getVertex(model, p1);
|
||||
if (0 != pushLink(model, &v1->faceLink, &v1->faceNum, newFaceIndex)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
edgeIndex = subdivEdgeByVertexs(model, p0, p1);
|
||||
if (-1 == edgeIndex) {
|
||||
fprintf(stderr, "%s:subdivEdgeByVertexs failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
e = getEdge(model, edgeIndex);
|
||||
if (0 != pushLink(model, &e->faceLink, &e->faceNum, newFaceIndex)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
f = getFace(model, newFaceIndex);
|
||||
if (0 != pushLink(model, &f->edgeLink, &f->edgeNum, edgeIndex)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (0 != pushLink(model, &f->vertexLink, &f->vertexNum, p1)) {
|
||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return newFaceIndex;
|
||||
}
|
||||
|
||||
int subdivAddTriangleFace(subdivModel *model, int p1, int p2, int p3) {
|
||||
int vertexs[3] = {p1, p2, p3};
|
||||
return subdivAddFace(model, vertexs, 3);
|
||||
}
|
||||
|
||||
int subdivAddQuadFace(subdivModel *model, int p1, int p2, int p3, int p4) {
|
||||
int vertexs[4] = {p1, p2, p3, p4};
|
||||
return subdivAddFace(model, vertexs, 4);
|
||||
}
|
||||
|
||||
int subdivAddCube(subdivModel *model) {
|
||||
int x, y, z;
|
||||
for (x = -1; x <= 1; x += 2) {
|
||||
for (y = -1; y <= 1; y += 2) {
|
||||
for (z = -1; z <= 1; z += 2) {
|
||||
vec3 v = {x, y, z};
|
||||
subdivAddVertex(model, &v);
|
||||
}
|
||||
}
|
||||
}
|
||||
subdivAddQuadFace(model, 0, 1, 3, 2);
|
||||
subdivAddQuadFace(model, 6, 7, 5, 4);
|
||||
subdivAddQuadFace(model, 4, 5, 1, 0);
|
||||
subdivAddQuadFace(model, 2, 3, 7, 6);
|
||||
subdivAddQuadFace(model, 0, 2, 6, 4);
|
||||
subdivAddQuadFace(model, 5, 7, 3, 1);
|
||||
subdivCalculteNorms(model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subdivModel *subdivCatmullClarkWithLoops(subdivModel *model, int loops) {
|
||||
int i;
|
||||
subdivModel *outputModel;
|
||||
outputModel = subdivCatmullClark(model);
|
||||
if (!outputModel) {
|
||||
fprintf(stderr, "%s:subdivCatmullClark failed.\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
for (i = 1; i < loops; ++i) {
|
||||
subdivModel *loopInput = outputModel;
|
||||
outputModel = subdivCatmullClark(loopInput);
|
||||
subdivDestroyModel(loopInput);
|
||||
if (!outputModel) {
|
||||
fprintf(stderr, "%s:subdivCatmullClark failed(loops:%d i:%d).\n",
|
||||
__FUNCTION__, loops, i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
drawDebugPrintf("faces: %d", outputModel->faceNum);
|
||||
drawModel(outputModel);
|
||||
return outputModel;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef SUBDIVIDE_H
|
||||
#define SUBDIVIDE_H
|
||||
#include "array.h"
|
||||
#include "3dstruct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct subdivModel subdivModel;
|
||||
|
||||
subdivModel *subdivCreateModel(void);
|
||||
void subdivDestroyModel(subdivModel *model);
|
||||
int subdivAddVertex(subdivModel *model, vec3 *v);
|
||||
int subdivAddTriangleFace(subdivModel *model, int p1, int p2, int p3);
|
||||
int subdivAddQuadFace(subdivModel *model, int p1, int p2, int p3, int p4);
|
||||
subdivModel *subdivCatmullClark(subdivModel *model);
|
||||
subdivModel *subdivCatmullClarkWithLoops(subdivModel *model, int loops);
|
||||
int subdivAddCube(subdivModel *model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue