diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-11-25 15:27:21 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-11-25 15:27:21 +0300 |
commit | 90cc7c8abd7b4c36002031edba8b75207fb98086 (patch) | |
tree | 3a0a63b907c87108164ee4562210c915e7c6d640 /source/blender/blenkernel/intern/CCGSubSurf.c | |
parent | 9a31f37d19de8ab6f45ac0622bd620e80cff9abf (diff) |
Sculpt: CCGSubsurf new functions to update normals, update subdivision
levels, copy coordinates from face grids, and stitch together face grids.
Diffstat (limited to 'source/blender/blenkernel/intern/CCGSubSurf.c')
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf.c | 1470 |
1 files changed, 898 insertions, 572 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index cee032f364e..86595dea8fb 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -1130,6 +1130,643 @@ CCGError ccgSubSurf_processSync(CCGSubSurf *ss) { return eCCGError_None; } +#define FACE_getIFNo(f, lvl, S, x, y) _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset) +#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) +static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + int numEffectedV, int numEffectedE, int numEffectedF) { + int i,ptrIdx; + int subdivLevels = ss->subdivLevels; + int lvl = ss->subdivLevels; + int edgeSize = 1 + (1<<lvl); + int gridSize = 1 + (1<<(lvl-1)); + int normalDataOffset = ss->normalDataOffset; + int vertDataSize = ss->meshIFC.vertDataSize; + + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + int S, x, y; + + for (S=0; S<f->numVerts; S++) { + for (y=0; y<gridSize-1; y++) + for (x=0; x<gridSize-1; x++) + NormZero(FACE_getIFNo(f, lvl, S, x, y)); + + if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected) + for (x=0; x<gridSize-1; x++) + NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1)); + if (FACE_getEdges(f)[S]->flags&Edge_eEffected) + for (y=0; y<gridSize-1; y++) + NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y)); + if (FACE_getVerts(f)[S]->flags&Vert_eEffected) + NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1)); + } + } + + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + int S, x, y; + float no[3]; + + for (S=0; S<f->numVerts; S++) { + int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected); + int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected); + int yLimitNext = xLimit; + int xLimitPrev = yLimit; + + for (y=0; y<gridSize - 1; y++) { + for (x=0; x<gridSize - 1; x++) { + int xPlusOk = (!xLimit || x<gridSize-2); + int yPlusOk = (!yLimit || y<gridSize-2); + + FACE_calcIFNo(f, lvl, S, x, y, no); + + NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no); + if (xPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no); + if (yPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no); + if (xPlusOk && yPlusOk) { + if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) { + NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no); + } + } + + if (x==0 && y==0) { + int K; + + if (!yLimitNext || 1<gridSize-1) + NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no); + if (!xLimitPrev || 1<gridSize-1) + NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no); + + for (K=0; K<f->numVerts; K++) { + if (K!=S) { + NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); + } + } + } else if (y==0) { + NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no); + if (!yLimitNext || x<gridSize-2) + NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no); + } else if (x==0) { + NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no); + if (!xLimitPrev || y<gridSize-2) + NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no); + } + } + } + } + } + // XXX can I reduce the number of normalisations here? + for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { + CCGVert *v = (CCGVert*) effectedV[ptrIdx]; + float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset); + + NormZero(no); + + for (i=0; i<v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1)); + } + + length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); + + if (length>FLT_EPSILON) { + float invLength = 1.0f/length; + no[0] *= invLength; + no[1] *= invLength; + no[2] *= invLength; + } else { + NormZero(no); + } + + for (i=0; i<v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no); + } + } + for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; + + if (e->numFaces) { + CCGFace *fLast = e->faces[e->numFaces-1]; + int x; + + for (i=0; i<e->numFaces-1; i++) { + CCGFace *f = e->faces[i]; + + for (x=1; x<edgeSize-1; x++) { + NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); + } + } + + for (i=0; i<e->numFaces-1; i++) { + CCGFace *f = e->faces[i]; + + for (x=1; x<edgeSize-1; x++) { + NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); + } + } + } + } + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + int S; + + for (S=0; S<f->numVerts; S++) { + NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1), + FACE_getIFNo(f, lvl, S, gridSize-1, 0)); + } + } + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + int S, x, y; + + for (S=0; S<f->numVerts; S++) { + for (y=0; y<gridSize; y++) { + for (x=0; x<gridSize; x++) { + float *no = FACE_getIFNo(f, lvl, S, x, y); + float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); + + if (length>FLT_EPSILON) { + float invLength = 1.0f/length; + no[0] *= invLength; + no[1] *= invLength; + no[2] *= invLength; + } else { + NormZero(no); + } + } + } + } + } +} +#undef FACE_getIFNo + +#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize) +#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize) +#define FACE_getIECo(f, lvl, S, x) _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) +#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) +static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) { + int subdivLevels = ss->subdivLevels; + int edgeSize = 1 + (1<<curLvl); + int gridSize = 1 + (1<<(curLvl-1)); + int nextLvl = curLvl+1; + int ptrIdx, S, y, x, i, cornerIdx; + void *q = ss->q, *r = ss->r; + int vertDataSize = ss->meshIFC.vertDataSize; + + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + + /* interior face midpoints + * o old interior face points + */ + for (S=0; S<f->numVerts; S++) { + for (y=0; y<gridSize-1; y++) { + for (x=0; x<gridSize-1; x++) { + int fx = 1 + 2*x; + int fy = 1 + 2*y; + void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0); + void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0); + void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1); + void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1); + void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3); + } + } + } + + /* interior edge midpoints + * o old interior edge points + * o new interior face midpoints + */ + for (S=0; S<f->numVerts; S++) { + for (x=0; x<gridSize-1; x++) { + int fx = x*2 + 1; + void *co0 = FACE_getIECo(f, curLvl, S, x+0); + void *co1 = FACE_getIECo(f, curLvl, S, x+1); + void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx); + void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); + void *co = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(co, co0, co1, co2, co3); + } + + /* interior face interior edge midpoints + * o old interior face points + * o new interior face midpoints + */ + + /* vertical */ + for (x=1; x<gridSize-1; x++) { + for (y=0; y<gridSize-1; y++) { + int fx = x*2; + int fy = y*2+1; + void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0); + void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1); + void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy); + void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy); + void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3); + } + } + + /* horizontal */ + for (y=1; y<gridSize-1; y++) { + for (x=0; x<gridSize-1; x++) { + int fx = x*2+1; + int fy = y*2; + void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y); + void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y); + void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1); + void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1); + void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3); + } + } + } + } + + /* exterior edge midpoints + * o old exterior edge points + * o new interior face midpoints + */ + for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (_edge_isBoundary(e) || sharpness>1.0) { + for (x=0; x<edgeSize-1; x++) { + int fx = x*2 + 1; + void *co0 = EDGE_getCo(e, curLvl, x+0); + void *co1 = EDGE_getCo(e, curLvl, x+1); + void *co = EDGE_getCo(e, nextLvl, fx); + + VertDataCopy(co, co0); + VertDataAdd(co, co1); + VertDataMulN(co, 0.5); + } + } else { + for (x=0; x<edgeSize-1; x++) { + int fx = x*2 + 1; + void *co0 = EDGE_getCo(e, curLvl, x+0); + void *co1 = EDGE_getCo(e, curLvl, x+1); + void *co = EDGE_getCo(e, nextLvl, fx); + int numFaces = 0; + + VertDataCopy(q, co0); + VertDataAdd(q, co1); + + for (i=0; i<e->numFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize)); + numFaces++; + } + + VertDataMulN(q, 1.0f/(2.0f+numFaces)); + + VertDataCopy(r, co0); + VertDataAdd(r, co1); + VertDataMulN(r, 0.5); + + VertDataCopy(co, q); + VertDataSub(r, q); + VertDataMulN(r, sharpness); + VertDataAdd(co, r); + } + } + } + + /* exterior vertex shift + * o old vertex points (shifting) + * o old exterior edge points + * o new interior face midpoints + */ + for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { + CCGVert *v = (CCGVert*) effectedV[ptrIdx]; + void *co = VERT_getCo(v, curLvl); + void *nCo = VERT_getCo(v, nextLvl); + int sharpCount = 0, allSharp = 1; + float avgSharpness = 0.0; + int seam = VERT_seam(v), seamEdges = 0; + + for (i=0; i<v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam && _edge_isBoundary(e)) + seamEdges++; + + if (sharpness!=0.0f) { + sharpCount++; + avgSharpness += sharpness; + } else { + allSharp = 0; + } + } + + if(sharpCount) { + avgSharpness /= sharpCount; + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } + } + + if (seam && seamEdges < 2) + seam = 0; + + if (!v->numEdges) { + VertDataCopy(nCo, co); + } else if (_vert_isBoundary(v)) { + int numBoundary = 0; + + VertDataZero(r); + for (i=0; i<v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + if (_edge_isBoundary(e)) { + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + numBoundary++; + } + } + + VertDataCopy(nCo, co); + VertDataMulN(nCo, 0.75); + VertDataMulN(r, 0.25f/numBoundary); + VertDataAdd(nCo, r); + } else { + int cornerIdx = (1 + (1<<(curLvl))) - 2; + int numEdges = 0, numFaces = 0; + + VertDataZero(q); + for (i=0; i<v->numFaces; i++) { + CCGFace *f = v->faces[i]; + VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx)); + numFaces++; + } + VertDataMulN(q, 1.0f/numFaces); + VertDataZero(r); + for (i=0; i<v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize)); + numEdges++; + } + VertDataMulN(r, 1.0f/numEdges); + + VertDataCopy(nCo, co); + VertDataMulN(nCo, numEdges-2.0f); + VertDataAdd(nCo, q); + VertDataAdd(nCo, r); + VertDataMulN(nCo, 1.0f/numEdges); + } + + if ((sharpCount>1 && v->numFaces) || seam) { + VertDataZero(q); + + if (seam) { + avgSharpness = 1.0f; + sharpCount = seamEdges; + allSharp = 1; + } + + for (i=0; i<v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam) { + if (_edge_isBoundary(e)) + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + } else if (sharpness != 0.0) { + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); + } + } + + VertDataMulN(q, (float) 1/sharpCount); + + if (sharpCount!=2 || allSharp) { + // q = q + (co-q)*avgSharpness + VertDataCopy(r, co); + VertDataSub(r, q); + VertDataMulN(r, avgSharpness); + VertDataAdd(q, r); + } + + // r = co*.75 + q*.25 + VertDataCopy(r, co); + VertDataMulN(r, .75); + VertDataMulN(q, .25); + VertDataAdd(r, q); + + // nCo = nCo + (r-nCo)*avgSharpness + VertDataSub(r, nCo); + VertDataMulN(r, avgSharpness); + VertDataAdd(nCo, r); + } + } + + /* exterior edge interior shift + * o old exterior edge midpoints (shifting) + * o old exterior edge midpoints + * o new interior face midpoints + */ + for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; + float sharpness = EDGE_getSharpness(e, curLvl); + int sharpCount = 0; + float avgSharpness = 0.0; + + if (sharpness!=0.0f) { + sharpCount = 2; + avgSharpness += sharpness; + + if (avgSharpness>1.0) { + avgSharpness = 1.0; + } + } else { + sharpCount = 0; + avgSharpness = 0; + } + + if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) { + for (x=1; x<edgeSize-1; x++) { + int fx = x*2; + void *co = EDGE_getCo(e, curLvl, x); + void *nCo = EDGE_getCo(e, nextLvl, fx); + VertDataCopy(r, EDGE_getCo(e, curLvl, x-1)); + VertDataAdd(r, EDGE_getCo(e, curLvl, x+1)); + VertDataMulN(r, 0.5); + VertDataCopy(nCo, co); + VertDataMulN(nCo, 0.75); + VertDataMulN(r, 0.25); + VertDataAdd(nCo, r); + } + } else { + for (x=1; x<edgeSize-1; x++) { + int fx = x*2; + void *co = EDGE_getCo(e, curLvl, x); + void *nCo = EDGE_getCo(e, nextLvl, fx); + int numFaces = 0; + + VertDataZero(q); + VertDataZero(r); + VertDataAdd(r, EDGE_getCo(e, curLvl, x-1)); + VertDataAdd(r, EDGE_getCo(e, curLvl, x+1)); + for (i=0; i<e->numFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize)); + VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize)); + + VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize)); + numFaces++; + } + VertDataMulN(q, 1.0/(numFaces*2.0f)); + VertDataMulN(r, 1.0/(2.0f + numFaces)); + + VertDataCopy(nCo, co); + VertDataMulN(nCo, (float) numFaces); + VertDataAdd(nCo, q); + VertDataAdd(nCo, r); + VertDataMulN(nCo, 1.0f/(2+numFaces)); + + if (sharpCount==2) { + VertDataCopy(q, co); + VertDataMulN(q, 6.0f); + VertDataAdd(q, EDGE_getCo(e, curLvl, x-1)); + VertDataAdd(q, EDGE_getCo(e, curLvl, x+1)); + VertDataMulN(q, 1/8.0f); + + VertDataSub(q, nCo); + VertDataMulN(q, avgSharpness); + VertDataAdd(nCo, q); + } + } + } + } + + for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + + /* interior center point shift + * o old face center point (shifting) + * o old interior edge points + * o new interior face midpoints + */ + VertDataZero(q); + for (S=0; S<f->numVerts; S++) { + VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1)); + } + VertDataMulN(q, 1.0f/f->numVerts); + VertDataZero(r); + for (S=0; S<f->numVerts; S++) { + VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1)); + } + VertDataMulN(r, 1.0f/f->numVerts); + + VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f); + VertDataAdd(FACE_getCenterData(f), q); + VertDataAdd(FACE_getCenterData(f), r); + VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts); + + for (S=0; S<f->numVerts; S++) { + /* interior face shift + * o old interior face point (shifting) + * o new interior edge midpoints + * o new interior face midpoints + */ + for (x=1; x<gridSize-1; x++) { + for (y=1; y<gridSize-1; y++) { + int fx = x*2; + int fy = y*2; + void *co = FACE_getIFCo(f, curLvl, S, x, y); + void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1), + FACE_getIFCo(f, nextLvl, S, fx+1, fy-1), + FACE_getIFCo(f, nextLvl, S, fx+1, fy+1), + FACE_getIFCo(f, nextLvl, S, fx-1, fy+1)); + + VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0), + FACE_getIFCo(f, nextLvl, S, fx+1, fy+0), + FACE_getIFCo(f, nextLvl, S, fx+0, fy-1), + FACE_getIFCo(f, nextLvl, S, fx+0, fy+1)); + + VertDataCopy(nCo, co); + VertDataSub(nCo, q); + VertDataMulN(nCo, 0.25f); + VertDataAdd(nCo, r); + } + } + + /* interior edge interior shift + * o old interior edge point (shifting) + * o new interior edge midpoints + * o new interior face midpoints + */ + for (x=1; x<gridSize-1; x++) { + int fx = x*2; + void *co = FACE_getIECo(f, curLvl, S, x); + void *nCo = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1), + FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1), + FACE_getIFCo(f, nextLvl, S, fx+1, +1), + FACE_getIFCo(f, nextLvl, S, fx-1, +1)); + + VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1), + FACE_getIECo(f, nextLvl, S, fx+1), + FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx), + FACE_getIFCo(f, nextLvl, S, fx, 1)); + + VertDataCopy(nCo, co); + VertDataSub(nCo, q); + VertDataMulN(nCo, 0.25f); + VertDataAdd(nCo, r); + } + } + } + + /* copy down */ + edgeSize = 1 + (1<<(nextLvl)); + gridSize = 1 + (1<<((nextLvl)-1)); + cornerIdx = gridSize-1; + for (i=0; i<numEffectedE; i++) { + CCGEdge *e = effectedE[i]; + VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl)); + VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl)); + } + for (i=0; i<numEffectedF; i++) { + CCGFace *f = effectedF[i]; + for (S=0; S<f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl)); + VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx)); + for (x=1; x<gridSize-1; x++) { + void *co = FACE_getIECo(f, nextLvl, S, x); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co); + VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co); + } + for (x=0; x<gridSize-1; x++) { + int eI = gridSize-1-x; + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize)); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize)); + } + } + } +} + + static void ccgSubSurf__sync(CCGSubSurf *ss) { CCGVert **effectedV; CCGEdge **effectedE; @@ -1137,11 +1774,9 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { int numEffectedV, numEffectedE, numEffectedF; int subdivLevels = ss->subdivLevels; int vertDataSize = ss->meshIFC.vertDataSize; - int i,ptrIdx,cornerIdx; - int S,x,y; - void *q = ss->q, *r = ss->r; + int i, j, ptrIdx, S; int curLvl, nextLvl; - int j; + void *q = ss->q, *r = ss->r; effectedV = CCGSUBSURF_alloc(ss, sizeof(*effectedV)*ss->vMap->numEntries); effectedE = CCGSUBSURF_alloc(ss, sizeof(*effectedE)*ss->eMap->numEntries); @@ -1172,10 +1807,6 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { } } -#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize) -#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize) -#define FACE_getIECo(f, lvl, S, x) _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) -#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) curLvl = 0; nextLvl = curLvl+1; @@ -1388,645 +2019,340 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { } for (curLvl=1; curLvl<subdivLevels; curLvl++) { - int edgeSize = 1 + (1<<curLvl); - int gridSize = 1 + (1<<(curLvl-1)); - nextLvl = curLvl+1; + ccgSubSurf__calcSubdivLevel(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF, curLvl); + } - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + if (ss->calcVertNormals) + ccgSubSurf__calcVertNormals(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF); - /* interior face midpoints - * o old interior face points - */ - for (S=0; S<f->numVerts; S++) { - for (y=0; y<gridSize-1; y++) { - for (x=0; x<gridSize-1; x++) { - int fx = 1 + 2*x; - int fy = 1 + 2*y; - void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0); - void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0); - void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1); - void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1); - void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3); - } - } - } + for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { + CCGVert *v = effectedV[ptrIdx]; + v->flags = 0; + } + for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { + CCGEdge *e = effectedE[ptrIdx]; + e->flags = 0; + } - /* interior edge midpoints - * o old interior edge points - * o new interior face midpoints - */ - for (S=0; S<f->numVerts; S++) { - for (x=0; x<gridSize-1; x++) { - int fx = x*2 + 1; - void *co0 = FACE_getIECo(f, curLvl, S, x+0); - void *co1 = FACE_getIECo(f, curLvl, S, x+1); - void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx); - void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); - void *co = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(co, co0, co1, co2, co3); - } + CCGSUBSURF_free(ss, effectedF); + CCGSUBSURF_free(ss, effectedE); + CCGSUBSURF_free(ss, effectedV); +} - /* interior face interior edge midpoints - * o old interior face points - * o new interior face midpoints - */ - - /* vertical */ - for (x=1; x<gridSize-1; x++) { - for (y=0; y<gridSize-1; y++) { - int fx = x*2; - int fy = y*2+1; - void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0); - void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1); - void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy); - void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy); - void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3); - } - } +static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces) +{ + CCGFace **array; + int i, num; - /* horizontal */ - for (y=1; y<gridSize-1; y++) { - for (x=0; x<gridSize-1; x++) { - int fx = x*2+1; - int fy = y*2; - void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y); - void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y); - void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1); - void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1); - void *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3); - } - } - } + if(!*faces) { + array = CCGSUBSURF_alloc(ss, sizeof(*array)*ss->fMap->numEntries); + num = 0; + for (i=0; i<ss->fMap->curSize; i++) { + CCGFace *f = (CCGFace*) ss->fMap->buckets[i]; + + for (; f; f = f->next) + array[num++] = f; } - /* exterior edge midpoints - * o old exterior edge points - * o new interior face midpoints - */ - for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); + *faces = array; + *numFaces = num; + *freeFaces= 1; + } + else + *freeFaces= 0; +} - if (_edge_isBoundary(e) || sharpness>1.0) { - for (x=0; x<edgeSize-1; x++) { - int fx = x*2 + 1; - void *co0 = EDGE_getCo(e, curLvl, x+0); - void *co1 = EDGE_getCo(e, curLvl, x+1); - void *co = EDGE_getCo(e, nextLvl, fx); +static void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges) +{ + CCGVert **arrayV; + CCGEdge **arrayE; + int numV, numE, i, j; - VertDataCopy(co, co0); - VertDataAdd(co, co1); - VertDataMulN(co, 0.5); - } - } else { - for (x=0; x<edgeSize-1; x++) { - int fx = x*2 + 1; - void *co0 = EDGE_getCo(e, curLvl, x+0); - void *co1 = EDGE_getCo(e, curLvl, x+1); - void *co = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataCopy(q, co0); - VertDataAdd(q, co1); - - for (i=0; i<e->numFaces; i++) { - CCGFace *f = e->faces[i]; - VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize)); - numFaces++; - } + arrayV = CCGSUBSURF_alloc(ss, sizeof(*arrayV)*ss->vMap->numEntries); + arrayE = CCGSUBSURF_alloc(ss, sizeof(*arrayE)*ss->eMap->numEntries); + numV = numE = 0; - VertDataMulN(q, 1.0f/(2.0f+numFaces)); + for (i=0; i<numFaces; i++) { + CCGFace *f = faces[i]; + f->flags |= Face_eEffected; + } - VertDataCopy(r, co0); - VertDataAdd(r, co1); - VertDataMulN(r, 0.5); + for (i=0; i<ss->vMap->curSize; i++) { + CCGVert *v = (CCGVert*) ss->vMap->buckets[i]; - VertDataCopy(co, q); - VertDataSub(r, q); - VertDataMulN(r, sharpness); - VertDataAdd(co, r); - } + for (; v; v = v->next) { + for(j=0; j<v->numFaces; j++) + if(!(v->faces[j]->flags & Face_eEffected)) + break; + + if(j == v->numFaces) { + arrayV[numV++] = v; + v->flags |= Vert_eEffected; } } + } - /* exterior vertex shift - * o old vertex points (shifting) - * o old exterior edge points - * o new interior face midpoints - */ - for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { - CCGVert *v = (CCGVert*) effectedV[ptrIdx]; - void *co = VERT_getCo(v, curLvl); - void *nCo = VERT_getCo(v, nextLvl); - int sharpCount = 0, allSharp = 1; - float avgSharpness = 0.0; - int seam = VERT_seam(v), seamEdges = 0; + for (i=0; i<ss->eMap->curSize; i++) { + CCGEdge *e = (CCGEdge*) ss->eMap->buckets[i]; - for (i=0; i<v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); + for (; e; e = e->next) { + for(j=0; j<e->numFaces; j++) + if(!(e->faces[j]->flags & Face_eEffected)) + break; + + if(j == e->numFaces) { + e->flags |= Edge_eEffected; + arrayE[numE++] = e; + } + } + } - if (seam && _edge_isBoundary(e)) - seamEdges++; + *verts = arrayV; + *numVerts = numV; + *edges = arrayE; + *numEdges = numE; +} - if (sharpness!=0.0f) { - sharpCount++; - avgSharpness += sharpness; - } else { - allSharp = 0; - } - } +/* copy face grid coordinates to other places */ +CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) +{ + int i, S, x, gridSize, cornerIdx, subdivLevels; + int vertDataSize = ss->meshIFC.vertDataSize, freeF; - if(sharpCount) { - avgSharpness /= sharpCount; - if (avgSharpness>1.0) { - avgSharpness = 1.0; - } - } + subdivLevels = ss->subdivLevels; + lvl = (lvl)? lvl: subdivLevels; + gridSize = 1 + (1<<(lvl-1)); + cornerIdx = gridSize-1; - if (seam && seamEdges < 2) - seam = 0; + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - if (!v->numEdges) { - VertDataCopy(nCo, co); - } else if (_vert_isBoundary(v)) { - int numBoundary = 0; + for (i=0; i<numEffectedF; i++) { + CCGFace *f = effectedF[i]; - VertDataZero(r); - for (i=0; i<v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - if (_edge_isBoundary(e)) { - VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); - numBoundary++; - } - } + for (S=0; S<f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts]; - VertDataCopy(nCo, co); - VertDataMulN(nCo, 0.75); - VertDataMulN(r, 0.25f/numBoundary); - VertDataAdd(nCo, r); - } else { - int cornerIdx = (1 + (1<<(curLvl))) - 2; - int numEdges = 0, numFaces = 0; + VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0)); + VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx)); - VertDataZero(q); - for (i=0; i<v->numFaces; i++) { - CCGFace *f = v->faces[i]; - VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx)); - numFaces++; - } - VertDataMulN(q, 1.0f/numFaces); - VertDataZero(r); - for (i=0; i<v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize)); - numEdges++; - } - VertDataMulN(r, 1.0f/numEdges); + for (x=0; x<gridSize; x++) + VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0)); - VertDataCopy(nCo, co); - VertDataMulN(nCo, numEdges-2.0f); - VertDataAdd(nCo, q); - VertDataAdd(nCo, r); - VertDataMulN(nCo, 1.0f/numEdges); + for (x=0; x<gridSize; x++) { + int eI = gridSize-1-x; + VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x)); + VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx)); } + } + } - if ((sharpCount>1 && v->numFaces) || seam) { - VertDataZero(q); - - if (seam) { - avgSharpness = 1.0f; - sharpCount = seamEdges; - allSharp = 1; - } + if(freeF) CCGSUBSURF_free(ss, effectedF); - for (i=0; i<v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); + return eCCGError_None; +} - if (seam) { - if (_edge_isBoundary(e)) - VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); - } else if (sharpness != 0.0) { - VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize)); - } - } +/* stitch together face grids, averaging coordinates at edges + and vertices, for multires displacements */ +CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) +{ + CCGVert **effectedV; + CCGEdge **effectedE; + int numEffectedV, numEffectedE, freeF; + int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize; + int vertDataSize = ss->meshIFC.vertDataSize; - VertDataMulN(q, (float) 1/sharpCount); + subdivLevels = ss->subdivLevels; + lvl = (lvl)? lvl: subdivLevels; + gridSize = 1 + (1<<(lvl-1)); + edgeSize = 1 + (1<<lvl); + cornerIdx = gridSize-1; - if (sharpCount!=2 || allSharp) { - // q = q + (co-q)*avgSharpness - VertDataCopy(r, co); - VertDataSub(r, q); - VertDataMulN(r, avgSharpness); - VertDataAdd(q, r); - } + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); + ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, + &effectedV, &numEffectedV, &effectedE, &numEffectedE); - // r = co*.75 + q*.25 - VertDataCopy(r, co); - VertDataMulN(r, .75); - VertDataMulN(q, .25); - VertDataAdd(r, q); + /* zero */ + for (i=0; i<numEffectedV; i++) { + CCGVert *v = effectedV[i]; + VertDataZero(VERT_getCo(v, lvl)); + } - // nCo = nCo + (r-nCo)*avgSharpness - VertDataSub(r, nCo); - VertDataMulN(r, avgSharpness); - VertDataAdd(nCo, r); - } - } + for (i=0; i<numEffectedE; i++) { + CCGEdge *e = effectedE[i]; - /* exterior edge interior shift - * o old exterior edge midpoints (shifting) - * o old exterior edge midpoints - * o new interior face midpoints - */ - for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); - int sharpCount = 0; - float avgSharpness = 0.0; + for (x=0; x<edgeSize; x++) + VertDataZero(EDGE_getCo(e, lvl, x)); + } - if (sharpness!=0.0f) { - sharpCount = 2; - avgSharpness += sharpness; + /* add */ + for (i=0; i<numEffectedF; i++) { + CCGFace *f = effectedF[i]; - if (avgSharpness>1.0) { - avgSharpness = 1.0; - } - } else { - sharpCount = 0; - avgSharpness = 0; - } + VertDataZero(FACE_getCenterData(f)); - if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) { - for (x=1; x<edgeSize-1; x++) { - int fx = x*2; - void *co = EDGE_getCo(e, curLvl, x); - void *nCo = EDGE_getCo(e, nextLvl, fx); - VertDataCopy(r, EDGE_getCo(e, curLvl, x-1)); - VertDataAdd(r, EDGE_getCo(e, curLvl, x+1)); - VertDataMulN(r, 0.5); - VertDataCopy(nCo, co); - VertDataMulN(nCo, 0.75); - VertDataMulN(r, 0.25); - VertDataAdd(nCo, r); - } - } else { - for (x=1; x<edgeSize-1; x++) { - int fx = x*2; - void *co = EDGE_getCo(e, curLvl, x); - void *nCo = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataZero(q); - VertDataZero(r); - VertDataAdd(r, EDGE_getCo(e, curLvl, x-1)); - VertDataAdd(r, EDGE_getCo(e, curLvl, x+1)); - for (i=0; i<e->numFaces; i++) { - CCGFace *f = e->faces[i]; - VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize)); - VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize)); - - VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize)); - numFaces++; - } - VertDataMulN(q, 1.0/(numFaces*2.0f)); - VertDataMulN(r, 1.0/(2.0f + numFaces)); + for (S=0; S<f->numVerts; S++) + for (x=0; x<gridSize; x++) + VertDataZero(FACE_getIECo(f, lvl, S, x)); - VertDataCopy(nCo, co); - VertDataMulN(nCo, (float) numFaces); - VertDataAdd(nCo, q); - VertDataAdd(nCo, r); - VertDataMulN(nCo, 1.0f/(2+numFaces)); - - if (sharpCount==2) { - VertDataCopy(q, co); - VertDataMulN(q, 6.0f); - VertDataAdd(q, EDGE_getCo(e, curLvl, x-1)); - VertDataAdd(q, EDGE_getCo(e, curLvl, x+1)); - VertDataMulN(q, 1/8.0f); - - VertDataSub(q, nCo); - VertDataMulN(q, avgSharpness); - VertDataAdd(nCo, q); - } - } - } - } + for (S=0; S<f->numVerts; S++) { + int prevS = (S+f->numVerts-1)%f->numVerts; + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[prevS]; - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; + VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0)); + VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx)); - /* interior center point shift - * o old face center point (shifting) - * o old interior edge points - * o new interior face midpoints - */ - VertDataZero(q); - for (S=0; S<f->numVerts; S++) { - VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1)); + for (x=1; x<gridSize-1; x++) { + VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0)); + VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x)); } - VertDataMulN(q, 1.0f/f->numVerts); - VertDataZero(r); - for (S=0; S<f->numVerts; S++) { - VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1)); - } - VertDataMulN(r, 1.0f/f->numVerts); - - VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f); - VertDataAdd(FACE_getCenterData(f), q); - VertDataAdd(FACE_getCenterData(f), r); - VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts); - - for (S=0; S<f->numVerts; S++) { - /* interior face shift - * o old interior face point (shifting) - * o new interior edge midpoints - * o new interior face midpoints - */ - for (x=1; x<gridSize-1; x++) { - for (y=1; y<gridSize-1; y++) { - int fx = x*2; - int fy = y*2; - void *co = FACE_getIFCo(f, curLvl, S, x, y); - void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1), - FACE_getIFCo(f, nextLvl, S, fx+1, fy-1), - FACE_getIFCo(f, nextLvl, S, fx+1, fy+1), - FACE_getIFCo(f, nextLvl, S, fx-1, fy+1)); - - VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0), - FACE_getIFCo(f, nextLvl, S, fx+1, fy+0), - FACE_getIFCo(f, nextLvl, S, fx+0, fy-1), - FACE_getIFCo(f, nextLvl, S, fx+0, fy+1)); - - VertDataCopy(nCo, co); - VertDataSub(nCo, q); - VertDataMulN(nCo, 0.25f); - VertDataAdd(nCo, r); - } - } - /* interior edge interior shift - * o old interior edge point (shifting) - * o new interior edge midpoints - * o new interior face midpoints - */ - for (x=1; x<gridSize-1; x++) { - int fx = x*2; - void *co = FACE_getIECo(f, curLvl, S, x); - void *nCo = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1), - FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1), - FACE_getIFCo(f, nextLvl, S, fx+1, +1), - FACE_getIFCo(f, nextLvl, S, fx-1, +1)); - - VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1), - FACE_getIECo(f, nextLvl, S, fx+1), - FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx), - FACE_getIFCo(f, nextLvl, S, fx, 1)); - - VertDataCopy(nCo, co); - VertDataSub(nCo, q); - VertDataMulN(nCo, 0.25f); - VertDataAdd(nCo, r); - } + for (x=0; x<gridSize-1; x++) { + int eI = gridSize-1-x; + VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x)); + if(x != 0) + VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx)); } } + } - /* copy down */ - edgeSize = 1 + (1<<(nextLvl)); - gridSize = 1 + (1<<((nextLvl)-1)); - cornerIdx = gridSize-1; - for (i=0; i<numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl)); - VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl)); - } - for (i=0; i<numEffectedF; i++) { - CCGFace *f = effectedF[i]; - for (S=0; S<f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f)); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f)); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl)); - VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx)); - for (x=1; x<gridSize-1; x++) { - void *co = FACE_getIECo(f, nextLvl, S, x); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co); - VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co); - } - for (x=0; x<gridSize-1; x++) { - int eI = gridSize-1-x; - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize)); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize)); - } - } - } + /* average */ + for (i=0; i<numEffectedV; i++) { + CCGVert *v = effectedV[i]; + VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces); } -#define FACE_getIFNo(f, lvl, S, x, y) _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset) -#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) - if (ss->calcVertNormals) { - int lvl = ss->subdivLevels; - int edgeSize = 1 + (1<<lvl); - int gridSize = 1 + (1<<(lvl-1)); - int normalDataOffset = ss->normalDataOffset; + for (i=0; i<numEffectedE; i++) { + CCGEdge *e = effectedE[i]; - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; - int S, x, y; + VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl)); + VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl)); - for (S=0; S<f->numVerts; S++) { - for (y=0; y<gridSize-1; y++) - for (x=0; x<gridSize-1; x++) - NormZero(FACE_getIFNo(f, lvl, S, x, y)); - - if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected) - for (x=0; x<gridSize-1; x++) - NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1)); - if (FACE_getEdges(f)[S]->flags&Edge_eEffected) - for (y=0; y<gridSize-1; y++) - NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y)); - if (FACE_getVerts(f)[S]->flags&Vert_eEffected) - NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1)); - } - } + for (x=1; x<edgeSize-1; x++) + VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces); + } - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; - int S, x, y; - float no[3]; + /* copy */ + for (i=0; i<numEffectedF; i++) { + CCGFace *f = effectedF[i]; - for (S=0; S<f->numVerts; S++) { - int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected); - int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected); - int yLimitNext = xLimit; - int xLimitPrev = yLimit; - - for (y=0; y<gridSize - 1; y++) { - for (x=0; x<gridSize - 1; x++) { - int xPlusOk = (!xLimit || x<gridSize-2); - int yPlusOk = (!yLimit || y<gridSize-2); - - FACE_calcIFNo(f, lvl, S, x, y, no); - - NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no); - if (xPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no); - if (yPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no); - if (xPlusOk && yPlusOk) { - if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) { - NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no); - } - } + VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts); - if (x==0 && y==0) { - int K; + for (S=0; S<f->numVerts; S++) + for (x=1; x<gridSize-1; x++) + VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f); - if (!yLimitNext || 1<gridSize-1) - NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no); - if (!xLimitPrev || 1<gridSize-1) - NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no); + for (S=0; S<f->numVerts; S++) { + int prevS = (S+f->numVerts-1)%f->numVerts; + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[prevS]; - for (K=0; K<f->numVerts; K++) { - if (K!=S) { - NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); - } - } - } else if (y==0) { - NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no); - if (!yLimitNext || x<gridSize-2) - NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no); - } else if (x==0) { - NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no); - if (!xLimitPrev || y<gridSize-2) - NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no); - } - } - } + VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl)); + + for (x=1; x<gridSize-1; x++) { + VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x)); + VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x)); } + + for (x=0; x<gridSize-1; x++) { + int eI = gridSize-1-x; + VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize)); + VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize)); + } + + VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f)); + VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0)); } - // XXX can I reduce the number of normalisations here? - for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { - CCGVert *v = (CCGVert*) effectedV[ptrIdx]; - float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset); + } - NormZero(no); + for (i=0; i<numEffectedV; i++) + effectedV[i]->flags = 0; + for (i=0; i<numEffectedE; i++) + effectedE[i]->flags = 0; + for (i=0; i<numEffectedF; i++) + effectedF[i]->flags = 0; - for (i=0; i<v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1)); - } + CCGSUBSURF_free(ss, effectedE); + CCGSUBSURF_free(ss, effectedV); + if(freeF) CCGSUBSURF_free(ss, effectedF); - length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); + return eCCGError_None; +} - if (length>FLT_EPSILON) { - float invLength = 1.0f/length; - no[0] *= invLength; - no[1] *= invLength; - no[2] *= invLength; - } else { - NormZero(no); - } +/* update normals for specified faces */ +CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) { + CCGVert **effectedV; + CCGEdge **effectedE; + int i, numEffectedV, numEffectedE, freeF; - for (i=0; i<v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no); - } - } - for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge*) effectedE[ptrIdx]; + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); + ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, + &effectedV, &numEffectedV, &effectedE, &numEffectedE); - if (e->numFaces) { - CCGFace *fLast = e->faces[e->numFaces-1]; - int x; + if (ss->calcVertNormals) + ccgSubSurf__calcVertNormals(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF); - for (i=0; i<e->numFaces-1; i++) { - CCGFace *f = e->faces[i]; + for (i=0; i<numEffectedV; i++) + effectedV[i]->flags = 0; + for (i=0; i<numEffectedE; i++) + effectedE[i]->flags = 0; + for (i=0; i<numEffectedF; i++) + effectedF[i]->flags = 0; - for (x=1; x<edgeSize-1; x++) { - NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } + CCGSUBSURF_free(ss, effectedE); + CCGSUBSURF_free(ss, effectedV); + if(freeF) CCGSUBSURF_free(ss, effectedF); - for (i=0; i<e->numFaces-1; i++) { - CCGFace *f = e->faces[i]; + return eCCGError_None; +} - for (x=1; x<edgeSize-1; x++) { - NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - } - } - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; - int S; +/* compute subdivision levels from a given starting point, used by + multires subdivide/propagate, by filling in coordinates at a + certain level, and then subdividing that up to the highest level */ +CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) +{ + CCGVert **effectedV; + CCGEdge **effectedE; + int numEffectedV, numEffectedE, freeF, i; + int curLvl, subdivLevels = ss->subdivLevels; - for (S=0; S<f->numVerts; S++) { - NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1), - FACE_getIFNo(f, lvl, S, gridSize-1, 0)); - } - } - for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace*) effectedF[ptrIdx]; - int S, x, y; - - for (S=0; S<f->numVerts; S++) { - for (y=0; y<gridSize; y++) { - for (x=0; x<gridSize; x++) { - float *no = FACE_getIFNo(f, lvl, S, x, y); - float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]); - - if (length>FLT_EPSILON) { - float invLength = 1.0f/length; - no[0] *= invLength; - no[1] *= invLength; - no[2] *= invLength; - } else { - NormZero(no); - } - } - } - } - } - } -#undef FACE_getIFNo + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); + ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, + &effectedV, &numEffectedV, &effectedE, &numEffectedE); - for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - v->flags = 0; - } - for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - e->flags = 0; + for (curLvl=lvl; curLvl<subdivLevels; curLvl++) { + ccgSubSurf__calcSubdivLevel(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF, curLvl); } -#undef VERT_getCo -#undef EDGE_getCo -#undef FACE_getIECo -#undef FACE_getIFCo + for (i=0; i<numEffectedV; i++) + effectedV[i]->flags = 0; + for (i=0; i<numEffectedE; i++) + effectedE[i]->flags = 0; + for (i=0; i<numEffectedF; i++) + effectedF[i]->flags = 0; - CCGSUBSURF_free(ss, effectedF); CCGSUBSURF_free(ss, effectedE); CCGSUBSURF_free(ss, effectedV); + if(freeF) CCGSUBSURF_free(ss, effectedF); + + return eCCGError_None; } +#undef VERT_getCo +#undef EDGE_getCo +#undef FACE_getIECo +#undef FACE_getIFCo + /*** External API accessor functions ***/ int ccgSubSurf_getNumVerts(CCGSubSurf *ss) { |