Blender V2.61 - r43446

CCGSubSurf.c

Go to the documentation of this file.
00001 
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <math.h>
00009 
00010 #include "CCGSubSurf.h"
00011 
00012 #include "MEM_guardedalloc.h"
00013 #include "BLO_sys_types.h" // for intptr_t support
00014 
00015 #ifdef _MSC_VER
00016 #define CCG_INLINE __inline
00017 #else
00018 #define CCG_INLINE inline
00019 #endif
00020 
00021 /* copied from BKE_utildefines.h ugh */
00022 #ifdef __GNUC__
00023 #  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
00024 #else
00025 #  define UNUSED(x) x
00026 #endif
00027 
00028 /* used for normalize_v3 in BLI_math_vector
00029  * float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */
00030 #define EPSILON (1.0e-35f)
00031 
00032 /***/
00033 
00034 typedef unsigned char   byte;
00035 
00036 /***/
00037 
00038 static int kHashSizes[] = {
00039     1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 
00040     16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, 
00041     4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459
00042 };
00043 
00044 typedef struct _EHEntry EHEntry;
00045 struct _EHEntry {
00046     EHEntry *next;
00047     void *key;
00048 };
00049 typedef struct _EHash {
00050     EHEntry **buckets;
00051     int numEntries, curSize, curSizeIdx;
00052 
00053     CCGAllocatorIFC allocatorIFC;
00054     CCGAllocatorHDL allocator;
00055 } EHash;
00056 
00057 #define EHASH_alloc(eh, nb)         ((eh)->allocatorIFC.alloc((eh)->allocator, nb))
00058 #define EHASH_free(eh, ptr)         ((eh)->allocatorIFC.free((eh)->allocator, ptr))
00059 
00060 #define EHASH_hash(eh, item)    (((uintptr_t) (item))%((unsigned int) (eh)->curSize))
00061 
00062 static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
00063     EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh));
00064     eh->allocatorIFC = *allocatorIFC;
00065     eh->allocator = allocator;
00066     eh->numEntries = 0;
00067     eh->curSizeIdx = 0;
00068     while (kHashSizes[eh->curSizeIdx]<estimatedNumEntries)
00069         eh->curSizeIdx++;
00070     eh->curSize = kHashSizes[eh->curSizeIdx];
00071     eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
00072     memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
00073 
00074     return eh;
00075 }
00076 typedef void (*EHEntryFreeFP)(EHEntry *, void *);
00077 static void _ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) {
00078     int numBuckets = eh->curSize;
00079 
00080     while (numBuckets--) {
00081         EHEntry *entry = eh->buckets[numBuckets];
00082 
00083         while (entry) {
00084             EHEntry *next = entry->next;
00085 
00086             freeEntry(entry, userData);
00087 
00088             entry = next;
00089         }
00090     }
00091 
00092     EHASH_free(eh, eh->buckets);
00093     EHASH_free(eh, eh);
00094 }
00095 
00096 static void _ehash_insert(EHash *eh, EHEntry *entry) {
00097     int numBuckets = eh->curSize;
00098     int hash = EHASH_hash(eh, entry->key);
00099     entry->next = eh->buckets[hash];
00100     eh->buckets[hash] = entry;
00101     eh->numEntries++;
00102 
00103     if (eh->numEntries > (numBuckets*3)) {
00104         EHEntry **oldBuckets = eh->buckets;
00105         eh->curSize = kHashSizes[++eh->curSizeIdx];
00106         
00107         eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
00108         memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
00109 
00110         while (numBuckets--) {
00111             for (entry = oldBuckets[numBuckets]; entry;) {
00112                 EHEntry *next = entry->next;
00113                 
00114                 hash = EHASH_hash(eh, entry->key);
00115                 entry->next = eh->buckets[hash];
00116                 eh->buckets[hash] = entry;
00117                 
00118                 entry = next;
00119             }
00120         }
00121 
00122         EHASH_free(eh, oldBuckets);
00123     }
00124 }
00125 
00126 static void *_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) {
00127     int hash = EHASH_hash(eh, key);
00128     void **prevp = (void**) &eh->buckets[hash];
00129     EHEntry *entry;
00130     
00131     for (; (entry = *prevp); prevp = (void**) &entry->next) {
00132         if (entry->key==key) {
00133             *prevp_r = (void**) prevp;
00134             return entry;
00135         }
00136     }
00137     
00138     return NULL;
00139 }
00140 
00141 static void *_ehash_lookup(EHash *eh, void *key) {
00142     int hash = EHASH_hash(eh, key);
00143     EHEntry *entry;
00144     
00145     for (entry = eh->buckets[hash]; entry; entry = entry->next)
00146         if (entry->key==key)
00147             break;
00148     
00149     return entry;
00150 }
00151 
00152 
00153 
00154 typedef struct _EHashIterator {
00155     EHash *eh;
00156     int curBucket;
00157     EHEntry *curEntry;
00158 } EHashIterator;
00159 
00160 static EHashIterator *_ehashIterator_new(EHash *eh) {
00161     EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi));
00162     ehi->eh = eh;
00163     ehi->curEntry = NULL;
00164     ehi->curBucket = -1;
00165     while (!ehi->curEntry) {
00166         ehi->curBucket++;
00167         if (ehi->curBucket==ehi->eh->curSize)
00168             break;
00169         ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
00170     }
00171     return ehi;
00172 }
00173 static void _ehashIterator_free(EHashIterator *ehi) {
00174     EHASH_free(ehi->eh, ehi);
00175 }
00176 
00177 static void *_ehashIterator_getCurrent(EHashIterator *ehi) {
00178     return ehi->curEntry;
00179 }
00180 
00181 static void _ehashIterator_next(EHashIterator *ehi) {
00182     if (ehi->curEntry) {
00183         ehi->curEntry = ehi->curEntry->next;
00184         while (!ehi->curEntry) {
00185             ehi->curBucket++;
00186             if (ehi->curBucket==ehi->eh->curSize)
00187                 break;
00188             ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
00189         }
00190     }
00191 }
00192 static int _ehashIterator_isStopped(EHashIterator *ehi) {
00193     return !ehi->curEntry;
00194 }
00195 
00196 /***/
00197 
00198 static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) {
00199     return malloc(numBytes);
00200 }
00201 static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a), void *ptr, int newSize, int UNUSED(oldSize)) {
00202     return realloc(ptr, newSize);
00203 }
00204 static void _stdAllocator_free(CCGAllocatorHDL UNUSED(a), void *ptr) {
00205     free(ptr);
00206 }
00207 
00208 static CCGAllocatorIFC *_getStandardAllocatorIFC(void) {
00209     static CCGAllocatorIFC ifc;
00210 
00211     ifc.alloc = _stdAllocator_alloc;
00212     ifc.realloc = _stdAllocator_realloc;
00213     ifc.free = _stdAllocator_free;
00214     ifc.release = NULL;
00215 
00216     return &ifc;
00217 }
00218 
00219 /***/
00220 
00221 static int VertDataEqual(const float *a, const float *b) {
00222     return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
00223 }
00224 #define VertDataZero(av)                { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
00225 #define VertDataCopy(av, bv)            { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
00226 #define VertDataAdd(av, bv)             { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
00227 #define VertDataSub(av, bv)             { float *_a = (float*) av, *_b = (float*) bv; _a[0]-=_b[0]; _a[1]-=_b[1]; _a[2]-=_b[2]; }
00228 #define VertDataMulN(av, n)             { float *_a = (float*) av; _a[0]*=n; _a[1]*=n; _a[2]*=n; }
00229 #define VertDataAvg4(tv, av, bv, cv, dv) \
00230     { \
00231         float *_t = (float*) tv, *_a = (float*) av, *_b = (float*) bv, *_c = (float*) cv, *_d = (float*) dv; \
00232         _t[0] = (_a[0]+_b[0]+_c[0]+_d[0])*.25f; \
00233         _t[1] = (_a[1]+_b[1]+_c[1]+_d[1])*.25f; \
00234         _t[2] = (_a[2]+_b[2]+_c[2]+_d[2])*.25f; \
00235     }
00236 #define NormZero(av)                    { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
00237 #define NormCopy(av, bv)                { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
00238 #define NormAdd(av, bv)                 { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
00239 
00240 
00241 static int _edge_isBoundary(const CCGEdge *e);
00242 
00243 /***/
00244 
00245 enum {
00246     Vert_eEffected=     (1<<0),
00247     Vert_eChanged=      (1<<1),
00248     Vert_eSeam=         (1<<2),
00249 } /*VertFlags*/;
00250 enum {
00251     Edge_eEffected=     (1<<0),
00252 } /*CCGEdgeFlags*/;
00253 enum {
00254     Face_eEffected=     (1<<0),
00255 } /*FaceFlags*/;
00256 
00257 struct _CCGVert {
00258     CCGVert     *next;  /* EHData.next */
00259     CCGVertHDL  vHDL;   /* EHData.key */
00260 
00261     short numEdges, numFaces, flags, pad;
00262 
00263     CCGEdge **edges;
00264     CCGFace **faces;
00265 //  byte *levelData;
00266 //  byte *userData;
00267 };
00268 #define VERT_getLevelData(v)        ((byte*) &(v)[1])
00269 
00270 struct _CCGEdge {
00271     CCGEdge     *next;  /* EHData.next */
00272     CCGEdgeHDL  eHDL;   /* EHData.key */
00273 
00274     short numFaces, flags;
00275     float crease;
00276 
00277     CCGVert *v0,*v1;
00278     CCGFace **faces;
00279 
00280 //  byte *levelData;
00281 //  byte *userData;
00282 };
00283 #define EDGE_getLevelData(e)        ((byte*) &(e)[1])
00284 
00285 struct _CCGFace {
00286     CCGFace     *next;  /* EHData.next */
00287     CCGFaceHDL  fHDL;   /* EHData.key */
00288 
00289     short numVerts, flags, pad1, pad2;
00290 
00291 //  CCGVert **verts;
00292 //  CCGEdge **edges;
00293 //  byte *centerData;
00294 //  byte **gridData;
00295 //  byte *userData;
00296 };
00297 #define FACE_getVerts(f)        ((CCGVert**) &(f)[1])
00298 #define FACE_getEdges(f)        ((CCGEdge**) &(FACE_getVerts(f)[(f)->numVerts]))
00299 #define FACE_getCenterData(f)   ((byte*) &(FACE_getEdges(f)[(f)->numVerts]))
00300 
00301 typedef enum {
00302     eSyncState_None = 0,
00303     eSyncState_Vert,
00304     eSyncState_Edge,
00305     eSyncState_Face,
00306     eSyncState_Partial,
00307 } SyncState;
00308 
00309 struct _CCGSubSurf {
00310     EHash *vMap;    /* map of CCGVertHDL -> Vert */
00311     EHash *eMap;    /* map of CCGEdgeHDL -> Edge */
00312     EHash *fMap;    /* map of CCGFaceHDL -> Face */
00313 
00314     CCGMeshIFC meshIFC;
00315     
00316     CCGAllocatorIFC allocatorIFC;
00317     CCGAllocatorHDL allocator;
00318 
00319     int subdivLevels;
00320     int numGrids;
00321     int allowEdgeCreation;
00322     float defaultCreaseValue;
00323     void *defaultEdgeUserData;
00324 
00325     void *q, *r;
00326         
00327         // data for calc vert normals
00328     int calcVertNormals;
00329     int normalDataOffset;
00330 
00331         // data for age'ing (to debug sync)
00332     int currentAge;
00333     int useAgeCounts;
00334     int vertUserAgeOffset;
00335     int edgeUserAgeOffset;
00336     int faceUserAgeOffset;
00337 
00338         // data used during syncing
00339     SyncState syncState;
00340 
00341     EHash *oldVMap, *oldEMap, *oldFMap;
00342     int lenTempArrays;
00343     CCGVert **tempVerts;
00344     CCGEdge **tempEdges;
00345 };
00346 
00347 #define CCGSUBSURF_alloc(ss, nb)            ((ss)->allocatorIFC.alloc((ss)->allocator, nb))
00348 #define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob))
00349 #define CCGSUBSURF_free(ss, ptr)            ((ss)->allocatorIFC.free((ss)->allocator, ptr))
00350 
00351 /***/
00352 
00353 static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss) {
00354     CCGVert *v = CCGSUBSURF_alloc(ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * (ss->subdivLevels+1) + ss->meshIFC.vertUserSize);
00355     byte *userData;
00356 
00357     v->vHDL = vHDL;
00358     v->edges = NULL;
00359     v->faces = NULL;
00360     v->numEdges = v->numFaces = 0;
00361     v->flags = 0;
00362 
00363     userData = ccgSubSurf_getVertUserData(ss, v);
00364     memset(userData, 0, ss->meshIFC.vertUserSize);
00365     if (ss->useAgeCounts) *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
00366 
00367     return v;
00368 }
00369 static void _vert_remEdge(CCGVert *v, CCGEdge *e) {
00370     int i;
00371     for (i=0; i<v->numEdges; i++) {
00372         if (v->edges[i]==e) {
00373             v->edges[i] = v->edges[--v->numEdges];
00374             break;
00375         }
00376     }
00377 }
00378 static void _vert_remFace(CCGVert *v, CCGFace *f) {
00379     int i;
00380     for (i=0; i<v->numFaces; i++) {
00381         if (v->faces[i]==f) {
00382             v->faces[i] = v->faces[--v->numFaces];
00383             break;
00384         }
00385     }
00386 }
00387 static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
00388     v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges+1)*sizeof(*v->edges), v->numEdges*sizeof(*v->edges));
00389     v->edges[v->numEdges++] = e;
00390 }
00391 static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
00392     v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces+1)*sizeof(*v->faces), v->numFaces*sizeof(*v->faces));
00393     v->faces[v->numFaces++] = f;
00394 }
00395 static CCGEdge *_vert_findEdgeTo(const CCGVert *v, const CCGVert *vQ) {
00396     int i;
00397     for (i=0; i<v->numEdges; i++) {
00398         CCGEdge *e = v->edges[v->numEdges-1-i]; // XXX, note reverse
00399         if (    (e->v0==v && e->v1==vQ) ||
00400                 (e->v1==v && e->v0==vQ))
00401             return e;
00402     }
00403     return NULL;
00404 }
00405 static int _vert_isBoundary(const CCGVert *v) {
00406     int i;
00407     for (i=0; i<v->numEdges; i++)
00408         if (_edge_isBoundary(v->edges[i]))
00409             return 1;
00410     return 0;
00411 }
00412 
00413 static void *_vert_getCo(CCGVert *v, int lvl, int dataSize) {
00414     return &VERT_getLevelData(v)[lvl*dataSize];
00415 }
00416 static float *_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) {
00417     return (float*) &VERT_getLevelData(v)[lvl*dataSize + normalDataOffset];
00418 }
00419 
00420 static void _vert_free(CCGVert *v, CCGSubSurf *ss) {
00421     CCGSUBSURF_free(ss, v->edges);
00422     CCGSUBSURF_free(ss, v->faces);
00423     CCGSUBSURF_free(ss, v);
00424 }
00425 
00426 static int VERT_seam(const CCGVert *v) {
00427     return ((v->flags & Vert_eSeam) != 0);
00428 }
00429 
00430 /***/
00431 
00432 static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss) {
00433     CCGEdge *e = CCGSUBSURF_alloc(ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1) + ss->meshIFC.edgeUserSize);
00434     byte *userData;
00435 
00436     e->eHDL = eHDL;
00437     e->v0 = v0;
00438     e->v1 = v1;
00439     e->crease = crease;
00440     e->faces = NULL;
00441     e->numFaces = 0;
00442     e->flags = 0;
00443     _vert_addEdge(v0, e, ss);
00444     _vert_addEdge(v1, e, ss);
00445 
00446     userData = ccgSubSurf_getEdgeUserData(ss, e);
00447     memset(userData, 0, ss->meshIFC.edgeUserSize);
00448     if (ss->useAgeCounts) *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
00449 
00450     return e;
00451 }
00452 static void _edge_remFace(CCGEdge *e, CCGFace *f) {
00453     int i;
00454     for (i=0; i<e->numFaces; i++) {
00455         if (e->faces[i]==f) {
00456             e->faces[i] = e->faces[--e->numFaces];
00457             break;
00458         }
00459     }
00460 }
00461 static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
00462     e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces+1)*sizeof(*e->faces), e->numFaces*sizeof(*e->faces));
00463     e->faces[e->numFaces++] = f;
00464 }
00465 static int _edge_isBoundary(const CCGEdge *e) {
00466     return e->numFaces<2;
00467 }
00468 
00469 static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) {
00470     if (vQ==e->v0) {
00471         return e->v1;
00472     } else {
00473         return e->v0;
00474     }
00475 }
00476 
00477 static void *_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) {
00478     int levelBase = lvl + (1<<lvl) - 1;
00479     return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
00480 }
00481 static float *_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset) {
00482     int levelBase = lvl + (1<<lvl) - 1;
00483     return (float*) &EDGE_getLevelData(e)[dataSize*(levelBase + x) + normalDataOffset];
00484 }
00485 static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) {
00486     int levelBase = lvl + (1<<lvl) - 1;
00487     if (v==e->v0) {
00488         return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
00489     } else {
00490         return &EDGE_getLevelData(e)[dataSize*(levelBase + (1<<lvl) - x)];      
00491     }
00492 }
00493 
00494 static void _edge_free(CCGEdge *e, CCGSubSurf *ss) {
00495     CCGSUBSURF_free(ss, e->faces);
00496     CCGSUBSURF_free(ss, e);
00497 }
00498 static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) {
00499     _vert_remEdge(e->v0, e);
00500     _vert_remEdge(e->v1, e);
00501     e->v0->flags |= Vert_eEffected;
00502     e->v1->flags |= Vert_eEffected;
00503     _edge_free(e, ss);
00504 }
00505 
00506 static float EDGE_getSharpness(CCGEdge *e, int lvl) {
00507     if (!lvl)
00508         return e->crease;
00509     else if (!e->crease)
00510         return 0.0f;
00511     else if (e->crease - lvl < 0.0f)
00512         return 0.0f;
00513     else
00514         return e->crease - lvl;
00515 }
00516 
00517 static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss) {
00518     int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
00519     CCGFace *f = CCGSUBSURF_alloc(ss, sizeof(CCGFace) + sizeof(CCGVert*)*numVerts + sizeof(CCGEdge*)*numVerts + ss->meshIFC.vertDataSize *(1 + numVerts*maxGridSize + numVerts*maxGridSize*maxGridSize) + ss->meshIFC.faceUserSize);
00520     byte *userData;
00521     int i;
00522 
00523     f->numVerts = numVerts;
00524     f->fHDL = fHDL;
00525     f->flags = 0;
00526 
00527     for (i=0; i<numVerts; i++) {
00528         FACE_getVerts(f)[i] = verts[i];
00529         FACE_getEdges(f)[i] = edges[i];
00530         _vert_addFace(verts[i], f, ss);
00531         _edge_addFace(edges[i], f, ss);
00532     }
00533 
00534     userData = ccgSubSurf_getFaceUserData(ss, f);
00535     memset(userData, 0, ss->meshIFC.faceUserSize);
00536     if (ss->useAgeCounts) *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
00537 
00538     return f;
00539 }
00540 
00541 static CCG_INLINE void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) {
00542     int maxGridSize = 1 + (1<<(levels-1));
00543     int spacing = 1<<(levels-lvl);
00544     byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
00545     return &gridBase[dataSize*x*spacing];
00546 }
00547 static CCG_INLINE void *_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) {
00548     int maxGridSize = 1 + (1<<(levels-1));
00549     int spacing = 1<<(levels-lvl);
00550     byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
00551     return &gridBase[dataSize*x*spacing + normalDataOffset];
00552 }
00553 static CCG_INLINE void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) {
00554     int maxGridSize = 1 + (1<<(levels-1));
00555     int spacing = 1<<(levels-lvl);
00556     byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
00557     return &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing)];
00558 }
00559 static CCG_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) {
00560     int maxGridSize = 1 + (1<<(levels-1));
00561     int spacing = 1<<(levels-lvl);
00562     byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
00563     return (float*) &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing) + normalDataOffset];
00564 }
00565 static int _face_getVertIndex(CCGFace *f, CCGVert *v) {
00566     int i;
00567     for (i=0; i<f->numVerts; i++)
00568         if (FACE_getVerts(f)[i]==v)
00569             return i;
00570     return -1;
00571 }
00572 static CCG_INLINE void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize) {
00573     int maxGridSize = 1 + (1<<(levels-1));
00574     int spacing = 1<<(levels-lvl);
00575     int S, x, y, cx, cy;
00576 
00577     for (S=0; S<f->numVerts; S++)
00578         if (FACE_getEdges(f)[S]==e)
00579             break;
00580 
00581     eX = eX*spacing;
00582     eY = eY*spacing;
00583     if (e->v0!=FACE_getVerts(f)[S]) {
00584         eX = (maxGridSize*2 - 1)-1 - eX;
00585     }
00586     y = maxGridSize - 1 - eX;
00587     x = maxGridSize - 1 - eY;
00588     if (x<0) {
00589         S = (S+f->numVerts-1)%f->numVerts;
00590         cx = y;
00591         cy = -x;
00592     } else if (y<0) {
00593         S = (S+1)%f->numVerts;
00594         cx = -y;
00595         cy = x;
00596     } else {
00597         cx = x;
00598         cy = y;
00599     }
00600     return _face_getIFCo(f, levels, S, cx, cy, levels, dataSize);
00601 }
00602 static float *_face_getIFNoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize, int normalDataOffset) {
00603     return (float*) ((byte*) _face_getIFCoEdge(f, e, lvl, eX, eY, levels, dataSize) + normalDataOffset);
00604 }
00605 static void _face_calcIFNo(CCGFace *f, int lvl, int S, int x, int y, float *no, int levels, int dataSize) {
00606     float *a = _face_getIFCo(f, lvl, S, x+0, y+0, levels, dataSize);
00607     float *b = _face_getIFCo(f, lvl, S, x+1, y+0, levels, dataSize);
00608     float *c = _face_getIFCo(f, lvl, S, x+1, y+1, levels, dataSize);
00609     float *d = _face_getIFCo(f, lvl, S, x+0, y+1, levels, dataSize);
00610     float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2];
00611     float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2];
00612     float length;
00613 
00614     no[0] = b_dY*a_cZ - b_dZ*a_cY;
00615     no[1] = b_dZ*a_cX - b_dX*a_cZ;
00616     no[2] = b_dX*a_cY - b_dY*a_cX;
00617 
00618     length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
00619 
00620     if (length>EPSILON) {
00621         float invLength = 1.f/length;
00622 
00623         no[0] *= invLength;
00624         no[1] *= invLength;
00625         no[2] *= invLength;
00626     } else {
00627         NormZero(no);
00628     }
00629 }
00630 
00631 static void _face_free(CCGFace *f, CCGSubSurf *ss) {
00632     CCGSUBSURF_free(ss, f);
00633 }
00634 static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) {
00635     int j;
00636     for (j=0; j<f->numVerts; j++) {
00637         _vert_remFace(FACE_getVerts(f)[j], f);
00638         _edge_remFace(FACE_getEdges(f)[j], f);
00639         FACE_getVerts(f)[j]->flags |= Vert_eEffected;
00640     }
00641     _face_free(f, ss);
00642 }
00643 
00644 /***/
00645 
00646 CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
00647     if (!allocatorIFC) {
00648         allocatorIFC = _getStandardAllocatorIFC();
00649         allocator = NULL;
00650     }
00651 
00652     if (subdivLevels<1) {
00653         return NULL;
00654     } else {
00655         CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
00656 
00657         ss->allocatorIFC = *allocatorIFC;
00658         ss->allocator = allocator;
00659 
00660         ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00661         ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00662         ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00663 
00664         ss->meshIFC = *ifc;
00665         
00666         ss->subdivLevels = subdivLevels;
00667         ss->numGrids = 0;
00668         ss->allowEdgeCreation = 0;
00669         ss->defaultCreaseValue = 0;
00670         ss->defaultEdgeUserData = NULL;
00671 
00672         ss->useAgeCounts = 0;
00673         ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
00674 
00675         ss->calcVertNormals = 0;
00676         ss->normalDataOffset = 0;
00677 
00678         ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
00679         ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
00680 
00681         ss->currentAge = 0;
00682 
00683         ss->syncState = eSyncState_None;
00684 
00685         ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
00686         ss->lenTempArrays = 0;
00687         ss->tempVerts = NULL;
00688         ss->tempEdges = NULL;   
00689 
00690         return ss;
00691     }
00692 }
00693 
00694 void ccgSubSurf_free(CCGSubSurf *ss) {
00695     CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
00696     CCGAllocatorHDL allocator = ss->allocator;
00697 
00698     if (ss->syncState) {
00699         _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss);
00700         _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss);
00701         _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
00702 
00703         MEM_freeN(ss->tempVerts);
00704         MEM_freeN(ss->tempEdges);
00705     }
00706 
00707     CCGSUBSURF_free(ss, ss->r);
00708     CCGSUBSURF_free(ss, ss->q);
00709     if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
00710 
00711     _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
00712     _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
00713     _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
00714 
00715     CCGSUBSURF_free(ss, ss);
00716 
00717     if (allocatorIFC.release) {
00718         allocatorIFC.release(allocator);
00719     }
00720 }
00721 
00722 CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData) {
00723     if (ss->defaultEdgeUserData) {
00724         CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
00725     }
00726 
00727     ss->allowEdgeCreation = !!allowEdgeCreation;
00728     ss->defaultCreaseValue = defaultCreaseValue;
00729     ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize);
00730 
00731     if (defaultUserData) {
00732         memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize);
00733     } else {
00734         memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
00735     }
00736 
00737     return eCCGError_None;
00738 }
00739 void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r) {
00740     if (allowEdgeCreation_r) *allowEdgeCreation_r = ss->allowEdgeCreation;
00741     if (ss->allowEdgeCreation) {
00742         if (defaultCreaseValue_r) *defaultCreaseValue_r = ss->defaultCreaseValue;
00743         if (defaultUserData_r) memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
00744     }
00745 }
00746 
00747 CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) {
00748     if (subdivisionLevels<=0) {
00749         return eCCGError_InvalidValue;
00750     } else if (subdivisionLevels!=ss->subdivLevels) {
00751         ss->numGrids = 0;
00752         ss->subdivLevels = subdivisionLevels;
00753         _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
00754         _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
00755         _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
00756         ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00757         ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00758         ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00759     }
00760 
00761     return eCCGError_None;
00762 }
00763 
00764 void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r)
00765 {
00766     *useAgeCounts_r = ss->useAgeCounts;
00767 
00768     if (vertUserOffset_r) *vertUserOffset_r = ss->vertUserAgeOffset;
00769     if (edgeUserOffset_r) *edgeUserOffset_r = ss->edgeUserAgeOffset;
00770     if (faceUserOffset_r) *faceUserOffset_r = ss->faceUserAgeOffset;
00771 }
00772 
00773 CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) {
00774     if (useAgeCounts) {
00775         if (    (vertUserOffset+4>ss->meshIFC.vertUserSize) ||
00776                 (edgeUserOffset+4>ss->meshIFC.edgeUserSize) ||
00777                 (faceUserOffset+4>ss->meshIFC.faceUserSize)) {
00778             return eCCGError_InvalidValue;
00779         }  else {
00780             ss->useAgeCounts = 1;
00781             ss->vertUserAgeOffset = vertUserOffset;
00782             ss->edgeUserAgeOffset = edgeUserOffset;
00783             ss->faceUserAgeOffset = faceUserOffset;
00784         }
00785     } else {
00786         ss->useAgeCounts = 0;
00787         ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
00788     }
00789 
00790     return eCCGError_None;
00791 }
00792 
00793 CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset) {
00794     if (useVertNormals) {
00795         if (normalDataOffset<0 || normalDataOffset+12>ss->meshIFC.vertDataSize) {
00796             return eCCGError_InvalidValue;
00797         } else {
00798             ss->calcVertNormals = 1;
00799             ss->normalDataOffset = normalDataOffset;
00800         }
00801     } else {
00802         ss->calcVertNormals = 0;
00803         ss->normalDataOffset = 0;
00804     }
00805 
00806     return eCCGError_None;
00807 }
00808 
00809 /***/
00810 
00811 CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) {
00812     if (ss->syncState!=eSyncState_None) {
00813         return eCCGError_InvalidSyncState;
00814     }
00815 
00816     ss->currentAge++;
00817 
00818     ss->oldVMap = ss->vMap; 
00819     ss->oldEMap = ss->eMap; 
00820     ss->oldFMap = ss->fMap;
00821 
00822     ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00823     ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00824     ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
00825 
00826     ss->numGrids = 0;
00827 
00828     ss->lenTempArrays = 12;
00829     ss->tempVerts = MEM_mallocN(sizeof(*ss->tempVerts)*ss->lenTempArrays, "CCGSubsurf tempVerts");
00830     ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges)*ss->lenTempArrays, "CCGSubsurf tempEdges");
00831 
00832     ss->syncState = eSyncState_Vert;
00833 
00834     return eCCGError_None;
00835 }
00836 
00837 CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) {
00838     if (ss->syncState!=eSyncState_None) {
00839         return eCCGError_InvalidSyncState;
00840     }
00841 
00842     ss->currentAge++;
00843 
00844     ss->syncState = eSyncState_Partial;
00845 
00846     return eCCGError_None;
00847 }
00848 
00849 CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) {
00850     if (ss->syncState!=eSyncState_Partial) {
00851         return eCCGError_InvalidSyncState;
00852     } else {
00853         void **prevp;
00854         CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
00855 
00856         if (!v || v->numFaces || v->numEdges) {
00857             return eCCGError_InvalidValue;
00858         } else {
00859             *prevp = v->next;
00860             _vert_free(v, ss);
00861         }
00862     }
00863 
00864     return eCCGError_None;
00865 }
00866 
00867 CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) {
00868     if (ss->syncState!=eSyncState_Partial) {
00869         return eCCGError_InvalidSyncState;
00870     } else {
00871         void **prevp;
00872         CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
00873 
00874         if (!e || e->numFaces) {
00875             return eCCGError_InvalidValue;
00876         } else {
00877             *prevp = e->next;
00878             _edge_unlinkMarkAndFree(e, ss);
00879         }
00880     }
00881 
00882     return eCCGError_None;
00883 }
00884 
00885 CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) {
00886     if (ss->syncState!=eSyncState_Partial) {
00887         return eCCGError_InvalidSyncState;
00888     } else {
00889         void **prevp;
00890         CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
00891 
00892         if (!f) {
00893             return eCCGError_InvalidValue;
00894         } else {
00895             *prevp = f->next;
00896             _face_unlinkMarkAndFree(f, ss);
00897         }
00898     }
00899 
00900     return eCCGError_None;
00901 }
00902 
00903 CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r) {
00904     void **prevp;
00905     CCGVert *v = NULL;
00906     short seamflag = (seam)? Vert_eSeam: 0;
00907     
00908     if (ss->syncState==eSyncState_Partial) {
00909         v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
00910         if (!v) {
00911             v = _vert_new(vHDL, ss);
00912             VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
00913             _ehash_insert(ss->vMap, (EHEntry*) v);
00914             v->flags = Vert_eEffected|seamflag;
00915         } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
00916             int i, j;
00917 
00918             VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
00919             v->flags = Vert_eEffected|seamflag;
00920 
00921             for (i=0; i<v->numEdges; i++) {
00922                 CCGEdge *e = v->edges[i];
00923                 e->v0->flags |= Vert_eEffected;
00924                 e->v1->flags |= Vert_eEffected;
00925             }
00926             for (i=0; i<v->numFaces; i++) {
00927                 CCGFace *f = v->faces[i];
00928                 for (j=0; j<f->numVerts; j++) {
00929                     FACE_getVerts(f)[j]->flags |= Vert_eEffected;
00930                 }
00931             }
00932         }
00933     } else {
00934         if (ss->syncState!=eSyncState_Vert) { 
00935             return eCCGError_InvalidSyncState;
00936         }
00937 
00938         v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
00939         if (!v) {
00940             v = _vert_new(vHDL, ss);
00941             VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
00942             _ehash_insert(ss->vMap, (EHEntry*) v);
00943             v->flags = Vert_eEffected|seamflag;
00944         } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
00945             *prevp = v->next;
00946             _ehash_insert(ss->vMap, (EHEntry*) v);
00947             VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
00948             v->flags = Vert_eEffected|Vert_eChanged|seamflag;
00949         } else {
00950             *prevp = v->next;
00951             _ehash_insert(ss->vMap, (EHEntry*) v);
00952             v->flags = 0;
00953         }
00954     }
00955 
00956     if (v_r) *v_r = v;
00957     return eCCGError_None;
00958 }
00959 
00960 CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r) {
00961     void **prevp;
00962     CCGEdge *e = NULL, *eNew;
00963 
00964     if (ss->syncState==eSyncState_Partial) {
00965         e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
00966         if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1 || crease!=e->crease) {
00967             CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
00968             CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
00969 
00970             eNew = _edge_new(eHDL, v0, v1, crease, ss);
00971 
00972             if (e) {
00973                 *prevp = eNew;
00974                 eNew->next = e->next;
00975 
00976                 _edge_unlinkMarkAndFree(e, ss);
00977             } else {
00978                 _ehash_insert(ss->eMap, (EHEntry*) eNew);
00979             }
00980 
00981             eNew->v0->flags |= Vert_eEffected;
00982             eNew->v1->flags |= Vert_eEffected;
00983         }
00984     } else {
00985         if (ss->syncState==eSyncState_Vert) {
00986             ss->syncState = eSyncState_Edge;
00987         } else if (ss->syncState!=eSyncState_Edge) {
00988             return eCCGError_InvalidSyncState;
00989         }
00990 
00991         e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
00992         if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1|| e->crease!=crease) {
00993             CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
00994             CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
00995             e = _edge_new(eHDL, v0, v1, crease, ss);
00996             _ehash_insert(ss->eMap, (EHEntry*) e);
00997             e->v0->flags |= Vert_eEffected;
00998             e->v1->flags |= Vert_eEffected;
00999         } else {
01000             *prevp = e->next;
01001             _ehash_insert(ss->eMap, (EHEntry*) e);
01002             e->flags = 0;
01003             if ((e->v0->flags|e->v1->flags)&Vert_eChanged) {
01004                 e->v0->flags |= Vert_eEffected;
01005                 e->v1->flags |= Vert_eEffected;
01006             }
01007         }
01008     }
01009 
01010     if (e_r) *e_r = e;
01011     return eCCGError_None;
01012 }
01013 
01014 CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r) {
01015     void **prevp;
01016     CCGFace *f = NULL, *fNew;
01017     int j, k, topologyChanged = 0;
01018 
01019     if (numVerts>ss->lenTempArrays) {
01020         ss->lenTempArrays = (numVerts<ss->lenTempArrays*2)?ss->lenTempArrays*2:numVerts;
01021         ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts)*ss->lenTempArrays);
01022         ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges)*ss->lenTempArrays);
01023     }
01024 
01025     if (ss->syncState==eSyncState_Partial) {
01026         f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
01027 
01028         for (k=0; k<numVerts; k++) {
01029             ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
01030         }
01031         for (k=0; k<numVerts; k++) {
01032             ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
01033         }
01034 
01035         if (f) {
01036             if (    f->numVerts!=numVerts ||
01037                     memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
01038                     memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
01039                 topologyChanged = 1;
01040         }
01041 
01042         if (!f || topologyChanged) {
01043             fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
01044 
01045             if (f) {
01046                 ss->numGrids += numVerts - f->numVerts;
01047 
01048                 *prevp = fNew;
01049                 fNew->next = f->next;
01050 
01051                 _face_unlinkMarkAndFree(f, ss);
01052             } else {
01053                 ss->numGrids += numVerts;
01054                 _ehash_insert(ss->fMap, (EHEntry*) fNew);
01055             }
01056 
01057             for (k=0; k<numVerts; k++)
01058                 FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
01059         }
01060     } else {
01061         if (ss->syncState==eSyncState_Vert || ss->syncState==eSyncState_Edge) {
01062             ss->syncState = eSyncState_Face;
01063         } else if (ss->syncState!=eSyncState_Face) {
01064             return eCCGError_InvalidSyncState;
01065         }
01066 
01067         f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
01068 
01069         for (k=0; k<numVerts; k++) {
01070             ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
01071 
01072             if (!ss->tempVerts[k])
01073                 return eCCGError_InvalidValue;
01074         }
01075         for (k=0; k<numVerts; k++) {
01076             ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
01077 
01078             if (!ss->tempEdges[k]) {
01079                 if (ss->allowEdgeCreation) {
01080                     CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) -1, ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts], ss->defaultCreaseValue, ss);
01081                     _ehash_insert(ss->eMap, (EHEntry*) e);
01082                     e->v0->flags |= Vert_eEffected;
01083                     e->v1->flags |= Vert_eEffected;
01084                     if (ss->meshIFC.edgeUserSize) {
01085                         memcpy(ccgSubSurf_getEdgeUserData(ss, e), ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
01086                     }
01087                 } else {
01088                     return eCCGError_InvalidValue;
01089                 }
01090             }
01091         }
01092 
01093         if (f) {
01094             if (    f->numVerts!=numVerts ||
01095                     memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
01096                     memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
01097                 topologyChanged = 1;
01098         }
01099 
01100         if (!f || topologyChanged) {
01101             f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
01102             _ehash_insert(ss->fMap, (EHEntry*) f);
01103             ss->numGrids += numVerts;
01104 
01105             for (k=0; k<numVerts; k++)
01106                 FACE_getVerts(f)[k]->flags |= Vert_eEffected;
01107         } else {
01108             *prevp = f->next;
01109             _ehash_insert(ss->fMap, (EHEntry*) f);
01110             f->flags = 0;
01111             ss->numGrids += f->numVerts;
01112 
01113             for (j=0; j<f->numVerts; j++) {
01114                 if (FACE_getVerts(f)[j]->flags&Vert_eChanged) {
01115                     for (k=0; k<f->numVerts; k++)
01116                         FACE_getVerts(f)[k]->flags |= Vert_eEffected;
01117                     break;
01118                 }
01119             }
01120         }
01121     }
01122 
01123     if (f_r) *f_r = f;
01124     return eCCGError_None;
01125 }
01126 
01127 static void ccgSubSurf__sync(CCGSubSurf *ss);
01128 CCGError ccgSubSurf_processSync(CCGSubSurf *ss) {
01129     if (ss->syncState==eSyncState_Partial) {
01130         ss->syncState = eSyncState_None;
01131 
01132         ccgSubSurf__sync(ss);
01133     } else if (ss->syncState) {
01134         _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss);
01135         _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss);
01136         _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
01137         MEM_freeN(ss->tempEdges);
01138         MEM_freeN(ss->tempVerts);
01139 
01140         ss->lenTempArrays = 0;
01141 
01142         ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
01143         ss->tempVerts = NULL;
01144         ss->tempEdges = NULL;
01145 
01146         ss->syncState = eSyncState_None;
01147 
01148         ccgSubSurf__sync(ss);
01149     } else {
01150         return eCCGError_InvalidSyncState;
01151     }
01152 
01153     return eCCGError_None;
01154 }
01155 
01156 #define VERT_getNo(e, lvl)                  _vert_getNo(e, lvl, vertDataSize, normalDataOffset)
01157 #define EDGE_getNo(e, lvl, x)               _edge_getNo(e, lvl, x, vertDataSize, normalDataOffset)
01158 #define FACE_getIFNo(f, lvl, S, x, y)       _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
01159 #define FACE_calcIFNo(f, lvl, S, x, y, no)  _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
01160 #define FACE_getIENo(f, lvl, S, x)          _face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset)
01161 static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
01162     CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
01163     int numEffectedV, int numEffectedE, int numEffectedF) {
01164     int i,ptrIdx;
01165     int subdivLevels = ss->subdivLevels;
01166     int lvl = ss->subdivLevels;
01167     int edgeSize = 1 + (1<<lvl);
01168     int gridSize = 1 + (1<<(lvl-1));
01169     int normalDataOffset = ss->normalDataOffset;
01170     int vertDataSize = ss->meshIFC.vertDataSize;
01171 
01172     #pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01173     for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
01174         CCGFace *f = (CCGFace*) effectedF[ptrIdx];
01175         int S, x, y;
01176         float no[3];
01177 
01178         for (S=0; S<f->numVerts; S++) {
01179             for (y=0; y<gridSize-1; y++)
01180                 for (x=0; x<gridSize-1; x++)
01181                     NormZero(FACE_getIFNo(f, lvl, S, x, y));
01182 
01183             if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected)
01184                 for (x=0; x<gridSize-1; x++)
01185                     NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1));
01186             if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
01187                 for (y=0; y<gridSize-1; y++)
01188                     NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y));
01189             if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
01190                 NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1));
01191         }
01192 
01193         for (S=0; S<f->numVerts; S++) {
01194             int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected);
01195             int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected);
01196             int yLimitNext = xLimit;
01197             int xLimitPrev = yLimit;
01198             
01199             for (y=0; y<gridSize - 1; y++) {
01200                 for (x=0; x<gridSize - 1; x++) {
01201                     int xPlusOk = (!xLimit || x<gridSize-2);
01202                     int yPlusOk = (!yLimit || y<gridSize-2);
01203 
01204                     FACE_calcIFNo(f, lvl, S, x, y, no);
01205 
01206                     NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no);
01207                     if (xPlusOk)
01208                         NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no);
01209                     if (yPlusOk)
01210                         NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no);
01211                     if (xPlusOk && yPlusOk) {
01212                         if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) {
01213                             NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no);
01214                         }
01215                     }
01216 
01217                     if (x==0 && y==0) {
01218                         int K;
01219 
01220                         if (!yLimitNext || 1<gridSize-1)
01221                             NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no);
01222                         if (!xLimitPrev || 1<gridSize-1)
01223                             NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no);
01224 
01225                         for (K=0; K<f->numVerts; K++) {
01226                             if (K!=S) {
01227                                 NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
01228                             }
01229                         }
01230                     } else if (y==0) {
01231                         NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no);
01232                         if (!yLimitNext || x<gridSize-2)
01233                             NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no);
01234                     } else if (x==0) {
01235                         NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no);
01236                         if (!xLimitPrev || y<gridSize-2)
01237                             NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no);
01238                     }
01239                 }
01240             }
01241         }
01242     }
01243         // XXX can I reduce the number of normalisations here?
01244     for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
01245         CCGVert *v = (CCGVert*) effectedV[ptrIdx];
01246         float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
01247 
01248         NormZero(no);
01249 
01250         for (i=0; i<v->numFaces; i++) {
01251             CCGFace *f = v->faces[i];
01252             NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1));
01253         }
01254 
01255         length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
01256 
01257         if (length>EPSILON) {
01258             float invLength = 1.0f/length;
01259             no[0] *= invLength;
01260             no[1] *= invLength;
01261             no[2] *= invLength;
01262         } else {
01263             NormZero(no);
01264         }
01265 
01266         for (i=0; i<v->numFaces; i++) {
01267             CCGFace *f = v->faces[i];
01268             NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no);
01269         }
01270     }
01271     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
01272         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
01273 
01274         if (e->numFaces) {
01275             CCGFace *fLast = e->faces[e->numFaces-1];
01276             int x;
01277 
01278             for (i=0; i<e->numFaces-1; i++) {
01279                 CCGFace *f = e->faces[i];
01280 
01281                 for (x=1; x<edgeSize-1; x++) {
01282                     NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
01283                             _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
01284                 }
01285             }
01286 
01287             for (i=0; i<e->numFaces-1; i++) {
01288                 CCGFace *f = e->faces[i];
01289 
01290                 for (x=1; x<edgeSize-1; x++) {
01291                     NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
01292                             _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
01293                 }
01294             }
01295         }
01296     }
01297 
01298     #pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01299     for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
01300         CCGFace *f = (CCGFace*) effectedF[ptrIdx];
01301         int S, x, y;
01302 
01303         for (S=0; S<f->numVerts; S++) {
01304             NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1),
01305                      FACE_getIFNo(f, lvl, S, gridSize-1, 0));
01306         }
01307 
01308         for (S=0; S<f->numVerts; S++) {
01309             for (y=0; y<gridSize; y++) {
01310                 for (x=0; x<gridSize; x++) {
01311                     float *no = FACE_getIFNo(f, lvl, S, x, y);
01312                     float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
01313 
01314                     if (length>EPSILON) {
01315                         float invLength = 1.0f/length;
01316                         no[0] *= invLength;
01317                         no[1] *= invLength;
01318                         no[2] *= invLength;
01319                     } else {
01320                         NormZero(no);
01321                     }
01322                 }
01323             }
01324 
01325             VertDataCopy((float*)((byte*)FACE_getCenterData(f) + normalDataOffset),
01326                 FACE_getIFNo(f, lvl, S, 0, 0));
01327 
01328             for (x=1; x<gridSize-1; x++)
01329                 NormCopy(FACE_getIENo(f, lvl, S, x),
01330                     FACE_getIFNo(f, lvl, S, x, 0));
01331         }
01332     }
01333 
01334     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
01335         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
01336 
01337         if (e->numFaces) {
01338             CCGFace *f = e->faces[0];
01339             int x;
01340 
01341             for (x=0; x<edgeSize; x++)
01342                 NormCopy(EDGE_getNo(e, lvl, x),
01343                     _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
01344         }
01345         else {
01346             /* set to zero here otherwise the normals are uninitialized memory
01347              * render: tests/animation/knight.blend with valgrind.
01348              * we could be more clever and interpolate vertex normals but these are
01349              * most likely not used so just zero out. */
01350             int x;
01351 
01352             for (x=0; x<edgeSize; x++) {
01353                 NormZero(EDGE_getNo(e, lvl, x));
01354             }
01355         }
01356     }
01357 }
01358 #undef FACE_getIFNo
01359 
01360 #define VERT_getCo(v, lvl)              _vert_getCo(v, lvl, vertDataSize)
01361 #define EDGE_getCo(e, lvl, x)           _edge_getCo(e, lvl, x, vertDataSize)
01362 #define FACE_getIECo(f, lvl, S, x)      _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
01363 #define FACE_getIFCo(f, lvl, S, x, y)   _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
01364 static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
01365     CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
01366     int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) {
01367     int subdivLevels = ss->subdivLevels;
01368     int edgeSize = 1 + (1<<curLvl);
01369     int gridSize = 1 + (1<<(curLvl-1));
01370     int nextLvl = curLvl+1;
01371     int ptrIdx, cornerIdx, i;
01372     int vertDataSize = ss->meshIFC.vertDataSize;
01373     void *q = ss->q, *r = ss->r;
01374 
01375     #pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01376     for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
01377         CCGFace *f = (CCGFace*) effectedF[ptrIdx];
01378         int S, x, y;
01379 
01380             /* interior face midpoints
01381              *  o old interior face points
01382              */
01383         for (S=0; S<f->numVerts; S++) {
01384             for (y=0; y<gridSize-1; y++) {
01385                 for (x=0; x<gridSize-1; x++) {
01386                     int fx = 1 + 2*x;
01387                     int fy = 1 + 2*y;
01388                     void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
01389                     void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
01390                     void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
01391                     void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
01392                     void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
01393 
01394                     VertDataAvg4(co, co0, co1, co2, co3);
01395                 }
01396             }
01397         }
01398 
01399             /* interior edge midpoints
01400              *  o old interior edge points
01401              *  o new interior face midpoints
01402              */
01403         for (S=0; S<f->numVerts; S++) {
01404             for (x=0; x<gridSize-1; x++) {
01405                 int fx = x*2 + 1;
01406                 void *co0 = FACE_getIECo(f, curLvl, S, x+0);
01407                 void *co1 = FACE_getIECo(f, curLvl, S, x+1);
01408                 void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
01409                 void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
01410                 void *co = FACE_getIECo(f, nextLvl, S, fx);
01411                 
01412                 VertDataAvg4(co, co0, co1, co2, co3);
01413             }
01414 
01415                     /* interior face interior edge midpoints
01416                      *  o old interior face points
01417                      *  o new interior face midpoints
01418                      */
01419 
01420                 /* vertical */
01421             for (x=1; x<gridSize-1; x++) {
01422                 for (y=0; y<gridSize-1; y++) {
01423                     int fx = x*2;
01424                     int fy = y*2+1;
01425                     void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
01426                     void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
01427                     void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
01428                     void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
01429                     void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
01430 
01431                     VertDataAvg4(co, co0, co1, co2, co3);
01432                 }
01433             }
01434 
01435                 /* horizontal */
01436             for (y=1; y<gridSize-1; y++) {
01437                 for (x=0; x<gridSize-1; x++) {
01438                     int fx = x*2+1;
01439                     int fy = y*2;
01440                     void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
01441                     void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
01442                     void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
01443                     void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
01444                     void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
01445 
01446                     VertDataAvg4(co, co0, co1, co2, co3);
01447                 }
01448             }
01449         }
01450     }
01451 
01452         /* exterior edge midpoints
01453          *  o old exterior edge points
01454          *  o new interior face midpoints
01455          */
01456     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
01457         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
01458         float sharpness = EDGE_getSharpness(e, curLvl);
01459         int x, j;
01460 
01461         if (_edge_isBoundary(e) || sharpness > 1.0f) {
01462             for (x=0; x<edgeSize-1; x++) {
01463                 int fx = x*2 + 1;
01464                 void *co0 = EDGE_getCo(e, curLvl, x+0);
01465                 void *co1 = EDGE_getCo(e, curLvl, x+1);
01466                 void *co = EDGE_getCo(e, nextLvl, fx);
01467 
01468                 VertDataCopy(co, co0);
01469                 VertDataAdd(co, co1);
01470                 VertDataMulN(co, 0.5f);
01471             }
01472         } else {
01473             for (x=0; x<edgeSize-1; x++) {
01474                 int fx = x*2 + 1;
01475                 void *co0 = EDGE_getCo(e, curLvl, x+0);
01476                 void *co1 = EDGE_getCo(e, curLvl, x+1);
01477                 void *co = EDGE_getCo(e, nextLvl, fx);
01478                 int numFaces = 0;
01479 
01480                 VertDataCopy(q, co0);
01481                 VertDataAdd(q, co1);
01482 
01483                 for (j=0; j<e->numFaces; j++) {
01484                     CCGFace *f = e->faces[j];
01485                     VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
01486                     numFaces++;
01487                 }
01488 
01489                 VertDataMulN(q, 1.0f/(2.0f+numFaces));
01490 
01491                 VertDataCopy(r, co0);
01492                 VertDataAdd(r, co1);
01493                 VertDataMulN(r, 0.5f);
01494 
01495                 VertDataCopy(co, q);
01496                 VertDataSub(r, q);
01497                 VertDataMulN(r, sharpness);
01498                 VertDataAdd(co, r);
01499             }
01500         }
01501     }
01502 
01503         /* exterior vertex shift
01504          *  o old vertex points (shifting)
01505          *  o old exterior edge points
01506          *  o new interior face midpoints
01507          */
01508     for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
01509         CCGVert *v = (CCGVert*) effectedV[ptrIdx];
01510         void *co = VERT_getCo(v, curLvl);
01511         void *nCo = VERT_getCo(v, nextLvl);
01512         int sharpCount = 0, allSharp = 1;
01513         float avgSharpness = 0.0;
01514         int j, seam = VERT_seam(v), seamEdges = 0;
01515 
01516         for (j=0; j<v->numEdges; j++) {
01517             CCGEdge *e = v->edges[j];
01518             float sharpness = EDGE_getSharpness(e, curLvl);
01519 
01520             if (seam && _edge_isBoundary(e))
01521                 seamEdges++;
01522 
01523             if (sharpness!=0.0f) {
01524                 sharpCount++;
01525                 avgSharpness += sharpness;
01526             } else {
01527                 allSharp = 0;
01528             }
01529         }
01530 
01531         if(sharpCount) {
01532             avgSharpness /= sharpCount;
01533             if (avgSharpness > 1.0f) {
01534                 avgSharpness = 1.0f;
01535             }
01536         }
01537 
01538         if (seamEdges < 2 || seamEdges != v->numEdges)
01539             seam = 0;
01540 
01541         if (!v->numEdges) {
01542             VertDataCopy(nCo, co);
01543         } else if (_vert_isBoundary(v)) {
01544             int numBoundary = 0;
01545 
01546             VertDataZero(r);
01547             for (j=0; j<v->numEdges; j++) {
01548                 CCGEdge *e = v->edges[j];
01549                 if (_edge_isBoundary(e)) {
01550                     VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
01551                     numBoundary++;
01552                 }
01553             }
01554 
01555             VertDataCopy(nCo, co);
01556             VertDataMulN(nCo, 0.75f);
01557             VertDataMulN(r, 0.25f/numBoundary);
01558             VertDataAdd(nCo, r);
01559         } else {
01560             int cornerIdx = (1 + (1<<(curLvl))) - 2;
01561             int numEdges = 0, numFaces = 0;
01562 
01563             VertDataZero(q);
01564             for (j=0; j<v->numFaces; j++) {
01565                 CCGFace *f = v->faces[j];
01566                 VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
01567                 numFaces++;
01568             }
01569             VertDataMulN(q, 1.0f/numFaces);
01570             VertDataZero(r);
01571             for (j=0; j<v->numEdges; j++) {
01572                 CCGEdge *e = v->edges[j];
01573                 VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
01574                 numEdges++;
01575             }
01576             VertDataMulN(r, 1.0f/numEdges);
01577 
01578             VertDataCopy(nCo, co);
01579             VertDataMulN(nCo, numEdges-2.0f);
01580             VertDataAdd(nCo, q);
01581             VertDataAdd(nCo, r);
01582             VertDataMulN(nCo, 1.0f/numEdges);
01583         }
01584 
01585         if ((sharpCount>1 && v->numFaces) || seam) {
01586             VertDataZero(q);
01587 
01588             if (seam) {
01589                 avgSharpness = 1.0f;
01590                 sharpCount = seamEdges;
01591                 allSharp = 1;
01592             }
01593 
01594             for (j=0; j<v->numEdges; j++) {
01595                 CCGEdge *e = v->edges[j];
01596                 float sharpness = EDGE_getSharpness(e, curLvl);
01597 
01598                 if (seam) {
01599                     if (_edge_isBoundary(e))
01600                         VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
01601                 } else if (sharpness != 0.0f) {
01602                     VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
01603                 }
01604             }
01605 
01606             VertDataMulN(q, (float) 1/sharpCount);
01607 
01608             if (sharpCount!=2 || allSharp) {
01609                     // q = q + (co-q)*avgSharpness
01610                 VertDataCopy(r, co);
01611                 VertDataSub(r, q);
01612                 VertDataMulN(r, avgSharpness);
01613                 VertDataAdd(q, r);
01614             }
01615 
01616                 // r = co*.75 + q*.25
01617             VertDataCopy(r, co);
01618             VertDataMulN(r, .75f);
01619             VertDataMulN(q, .25f);
01620             VertDataAdd(r, q);
01621 
01622                 // nCo = nCo  + (r-nCo)*avgSharpness
01623             VertDataSub(r, nCo);
01624             VertDataMulN(r, avgSharpness);
01625             VertDataAdd(nCo, r);
01626         }
01627     }
01628 
01629         /* exterior edge interior shift
01630          *  o old exterior edge midpoints (shifting)
01631          *  o old exterior edge midpoints
01632          *  o new interior face midpoints
01633          */
01634     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
01635         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
01636         float sharpness = EDGE_getSharpness(e, curLvl);
01637         int sharpCount = 0;
01638         float avgSharpness = 0.0;
01639         int x, j;
01640 
01641         if (sharpness!=0.0f) {
01642             sharpCount = 2;
01643             avgSharpness += sharpness;
01644 
01645             if (avgSharpness > 1.0f) {
01646                 avgSharpness = 1.0f;
01647             }
01648         } else {
01649             sharpCount = 0;
01650             avgSharpness = 0;
01651         }
01652 
01653         if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
01654             for (x=1; x<edgeSize-1; x++) {
01655                 int fx = x*2;
01656                 void *co = EDGE_getCo(e, curLvl, x);
01657                 void *nCo = EDGE_getCo(e, nextLvl, fx);
01658                 VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
01659                 VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
01660                 VertDataMulN(r, 0.5f);
01661                 VertDataCopy(nCo, co);
01662                 VertDataMulN(nCo, 0.75f);
01663                 VertDataMulN(r, 0.25f);
01664                 VertDataAdd(nCo, r);
01665             }
01666         } else {
01667             for (x=1; x<edgeSize-1; x++) {
01668                 int fx = x*2;
01669                 void *co = EDGE_getCo(e, curLvl, x);
01670                 void *nCo = EDGE_getCo(e, nextLvl, fx);
01671                 int numFaces = 0;
01672 
01673                 VertDataZero(q);
01674                 VertDataZero(r);
01675                 VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
01676                 VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
01677                 for (j=0; j<e->numFaces; j++) {
01678                     CCGFace *f = e->faces[j];
01679                     VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
01680                     VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
01681 
01682                     VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
01683                     numFaces++;
01684                 }
01685                 VertDataMulN(q, 1.0f/(numFaces*2.0f));
01686                 VertDataMulN(r, 1.0f/(2.0f + numFaces));
01687 
01688                 VertDataCopy(nCo, co);
01689                 VertDataMulN(nCo, (float) numFaces);
01690                 VertDataAdd(nCo, q);
01691                 VertDataAdd(nCo, r);
01692                 VertDataMulN(nCo, 1.0f/(2+numFaces));
01693 
01694                 if (sharpCount==2) {
01695                     VertDataCopy(q, co);
01696                     VertDataMulN(q, 6.0f);
01697                     VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
01698                     VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
01699                     VertDataMulN(q, 1/8.0f);
01700 
01701                     VertDataSub(q, nCo);
01702                     VertDataMulN(q, avgSharpness);
01703                     VertDataAdd(nCo, q);
01704                 }
01705             }
01706         }
01707     }
01708 
01709     #pragma omp parallel private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01710     {
01711         void *q, *r;
01712 
01713         #pragma omp critical
01714         {
01715             q = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q");
01716             r = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r");
01717         }
01718 
01719         #pragma omp for schedule(static)
01720         for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
01721             CCGFace *f = (CCGFace*) effectedF[ptrIdx];
01722             int S, x, y;
01723 
01724                 /* interior center point shift
01725                  *  o old face center point (shifting)
01726                  *  o old interior edge points
01727                  *  o new interior face midpoints
01728                  */
01729             VertDataZero(q);
01730             for (S=0; S<f->numVerts; S++) {
01731                 VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
01732             }
01733             VertDataMulN(q, 1.0f/f->numVerts);
01734             VertDataZero(r);
01735             for (S=0; S<f->numVerts; S++) {
01736                 VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
01737             }
01738             VertDataMulN(r, 1.0f/f->numVerts);
01739 
01740             VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
01741             VertDataAdd(FACE_getCenterData(f), q);
01742             VertDataAdd(FACE_getCenterData(f), r);
01743             VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
01744 
01745             for (S=0; S<f->numVerts; S++) {
01746                     /* interior face shift
01747                      *  o old interior face point (shifting)
01748                      *  o new interior edge midpoints
01749                      *  o new interior face midpoints
01750                      */
01751                 for (x=1; x<gridSize-1; x++) {
01752                     for (y=1; y<gridSize-1; y++) {
01753                         int fx = x*2;
01754                         int fy = y*2;
01755                         void *co = FACE_getIFCo(f, curLvl, S, x, y);
01756                         void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
01757                         
01758                         VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
01759                             FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
01760                             FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
01761                             FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
01762 
01763                         VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
01764                             FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
01765                             FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
01766                             FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
01767 
01768                         VertDataCopy(nCo, co);
01769                         VertDataSub(nCo, q);
01770                         VertDataMulN(nCo, 0.25f);
01771                         VertDataAdd(nCo, r);
01772                     }
01773                 }
01774 
01775                     /* interior edge interior shift
01776                      *  o old interior edge point (shifting)
01777                      *  o new interior edge midpoints
01778                      *  o new interior face midpoints
01779                      */
01780                 for (x=1; x<gridSize-1; x++) {
01781                     int fx = x*2;
01782                     void *co = FACE_getIECo(f, curLvl, S, x);
01783                     void *nCo = FACE_getIECo(f, nextLvl, S, fx);
01784                     
01785                     VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
01786                         FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
01787                         FACE_getIFCo(f, nextLvl, S, fx+1, +1),
01788                         FACE_getIFCo(f, nextLvl, S, fx-1, +1));
01789 
01790                     VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
01791                         FACE_getIECo(f, nextLvl, S, fx+1),
01792                         FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
01793                         FACE_getIFCo(f, nextLvl, S, fx, 1));
01794 
01795                     VertDataCopy(nCo, co);
01796                     VertDataSub(nCo, q);
01797                     VertDataMulN(nCo, 0.25f);
01798                     VertDataAdd(nCo, r);
01799                 }
01800             }
01801         }
01802 
01803         #pragma omp critical
01804         {
01805             MEM_freeN(q);
01806             MEM_freeN(r);
01807         }
01808     }
01809 
01810         /* copy down */
01811     edgeSize = 1 + (1<<(nextLvl));
01812     gridSize = 1 + (1<<((nextLvl)-1));
01813     cornerIdx = gridSize-1;
01814 
01815     #pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01816     for (i=0; i<numEffectedE; i++) {
01817         CCGEdge *e = effectedE[i];
01818         VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
01819         VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
01820     }
01821 
01822     #pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
01823     for (i=0; i<numEffectedF; i++) {
01824         CCGFace *f = effectedF[i];
01825         int S, x;
01826 
01827         for (S=0; S<f->numVerts; S++) {
01828             CCGEdge *e = FACE_getEdges(f)[S];
01829             CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
01830 
01831             VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
01832             VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
01833             VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
01834             VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
01835             for (x=1; x<gridSize-1; x++) {
01836                 void *co = FACE_getIECo(f, nextLvl, S, x);
01837                 VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
01838                 VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
01839             }
01840             for (x=0; x<gridSize-1; x++) {
01841                 int eI = gridSize-1-x;
01842                 VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
01843                 VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
01844             }
01845         }
01846     }
01847 }
01848 
01849 
01850 static void ccgSubSurf__sync(CCGSubSurf *ss) {
01851     CCGVert **effectedV;
01852     CCGEdge **effectedE;
01853     CCGFace **effectedF;
01854     int numEffectedV, numEffectedE, numEffectedF;
01855     int subdivLevels = ss->subdivLevels;
01856     int vertDataSize = ss->meshIFC.vertDataSize;
01857     int i, j, ptrIdx, S;
01858     int curLvl, nextLvl;
01859     void *q = ss->q, *r = ss->r;
01860 
01861     effectedV = MEM_mallocN(sizeof(*effectedV)*ss->vMap->numEntries, "CCGSubsurf effectedV");
01862     effectedE = MEM_mallocN(sizeof(*effectedE)*ss->eMap->numEntries, "CCGSubsurf effectedE");
01863     effectedF = MEM_mallocN(sizeof(*effectedF)*ss->fMap->numEntries, "CCGSubsurf effectedF");
01864     numEffectedV = numEffectedE = numEffectedF = 0;
01865     for (i=0; i<ss->vMap->curSize; i++) {
01866         CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
01867         for (; v; v = v->next) {
01868             if (v->flags&Vert_eEffected) {
01869                 effectedV[numEffectedV++] = v;
01870 
01871                 for (j=0; j<v->numEdges; j++) {
01872                     CCGEdge *e = v->edges[j];
01873                     if (!(e->flags&Edge_eEffected)) {
01874                         effectedE[numEffectedE++] = e;
01875                         e->flags |= Edge_eEffected;
01876                     }
01877                 }
01878 
01879                 for (j=0; j<v->numFaces; j++) {
01880                     CCGFace *f = v->faces[j];
01881                     if (!(f->flags&Face_eEffected)) {
01882                         effectedF[numEffectedF++] = f;
01883                         f->flags |= Face_eEffected;
01884                     }
01885                 }
01886             }
01887         }
01888     }
01889 
01890     curLvl = 0;
01891     nextLvl = curLvl+1;
01892 
01893     for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
01894         CCGFace *f = effectedF[ptrIdx];
01895         void *co = FACE_getCenterData(f);
01896         VertDataZero(co);
01897         for (i=0; i<f->numVerts; i++) {
01898             VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
01899         }
01900         VertDataMulN(co, 1.0f/f->numVerts);
01901 
01902         f->flags = 0;
01903     }
01904     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
01905         CCGEdge *e = effectedE[ptrIdx];
01906         void *co = EDGE_getCo(e, nextLvl, 1);
01907         float sharpness = EDGE_getSharpness(e, curLvl);
01908 
01909         if (_edge_isBoundary(e) || sharpness >= 1.0f) {
01910             VertDataCopy(co, VERT_getCo(e->v0, curLvl));
01911             VertDataAdd(co, VERT_getCo(e->v1, curLvl));
01912             VertDataMulN(co, 0.5f);
01913         } else {
01914             int numFaces = 0;
01915             VertDataCopy(q, VERT_getCo(e->v0, curLvl));
01916             VertDataAdd(q, VERT_getCo(e->v1, curLvl));
01917             for (i=0; i<e->numFaces; i++) {
01918                 CCGFace *f = e->faces[i];
01919                 VertDataAdd(q, FACE_getCenterData(f));
01920                 numFaces++;
01921             }
01922             VertDataMulN(q, 1.0f/(2.0f+numFaces));
01923 
01924             VertDataCopy(r, VERT_getCo(e->v0, curLvl));
01925             VertDataAdd(r, VERT_getCo(e->v1, curLvl));
01926             VertDataMulN(r, 0.5f);
01927 
01928             VertDataCopy(co, q);
01929             VertDataSub(r, q);
01930             VertDataMulN(r, sharpness);
01931             VertDataAdd(co, r);
01932         }
01933 
01934         // edge flags cleared later
01935     }
01936     for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
01937         CCGVert *v = effectedV[ptrIdx];
01938         void *co = VERT_getCo(v, curLvl);
01939         void *nCo = VERT_getCo(v, nextLvl);
01940         int sharpCount = 0, allSharp = 1;
01941         float avgSharpness = 0.0;
01942         int seam = VERT_seam(v), seamEdges = 0;
01943 
01944         for (i=0; i<v->numEdges; i++) {
01945             CCGEdge *e = v->edges[i];
01946             float sharpness = EDGE_getSharpness(e, curLvl);
01947 
01948             if (seam && _edge_isBoundary(e))
01949                 seamEdges++;
01950 
01951             if (sharpness!=0.0f) {
01952                 sharpCount++;
01953                 avgSharpness += sharpness;
01954             } else {
01955                 allSharp = 0;
01956             }
01957         }
01958 
01959         if(sharpCount) {
01960             avgSharpness /= sharpCount;
01961             if (avgSharpness > 1.0f) {
01962                 avgSharpness = 1.0f;
01963             }
01964         }
01965 
01966         if (seamEdges < 2 || seamEdges != v->numEdges)
01967             seam = 0;
01968 
01969         if (!v->numEdges) {
01970             VertDataCopy(nCo, co);
01971         } else if (_vert_isBoundary(v)) {
01972             int numBoundary = 0;
01973 
01974             VertDataZero(r);
01975             for (i=0; i<v->numEdges; i++) {
01976                 CCGEdge *e = v->edges[i];
01977                 if (_edge_isBoundary(e)) {
01978                     VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
01979                     numBoundary++;
01980                 }
01981             }
01982             VertDataCopy(nCo, co);
01983             VertDataMulN(nCo, 0.75f);
01984             VertDataMulN(r, 0.25f/numBoundary);
01985             VertDataAdd(nCo, r);
01986         } else {
01987             int numEdges = 0, numFaces = 0;
01988 
01989             VertDataZero(q);
01990             for (i=0; i<v->numFaces; i++) {
01991                 CCGFace *f = v->faces[i];
01992                 VertDataAdd(q, FACE_getCenterData(f));
01993                 numFaces++;
01994             }
01995             VertDataMulN(q, 1.0f/numFaces);
01996             VertDataZero(r);
01997             for (i=0; i<v->numEdges; i++) {
01998                 CCGEdge *e = v->edges[i];
01999                 VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
02000                 numEdges++;
02001             }
02002             VertDataMulN(r, 1.0f/numEdges);
02003 
02004             VertDataCopy(nCo, co);
02005             VertDataMulN(nCo, numEdges-2.0f);
02006             VertDataAdd(nCo, q);
02007             VertDataAdd(nCo, r);
02008             VertDataMulN(nCo, 1.0f/numEdges);
02009         }
02010 
02011         if (sharpCount>1 || seam) {
02012             VertDataZero(q);
02013 
02014             if (seam) {
02015                 avgSharpness = 1.0f;
02016                 sharpCount = seamEdges;
02017                 allSharp = 1;
02018             }
02019 
02020             for (i=0; i<v->numEdges; i++) {
02021                 CCGEdge *e = v->edges[i];
02022                 float sharpness = EDGE_getSharpness(e, curLvl);
02023 
02024                 if (seam) {
02025                     if (_edge_isBoundary(e)) {
02026                         CCGVert *oV = _edge_getOtherVert(e, v);
02027                         VertDataAdd(q, VERT_getCo(oV, curLvl));
02028                     }
02029                 } else if (sharpness != 0.0f) {
02030                     CCGVert *oV = _edge_getOtherVert(e, v);
02031                     VertDataAdd(q, VERT_getCo(oV, curLvl));
02032                 }
02033             }
02034 
02035             VertDataMulN(q, (float) 1/sharpCount);
02036 
02037             if (sharpCount!=2 || allSharp) {
02038                     // q = q + (co-q)*avgSharpness
02039                 VertDataCopy(r, co);
02040                 VertDataSub(r, q);
02041                 VertDataMulN(r, avgSharpness);
02042                 VertDataAdd(q, r);
02043             }
02044 
02045                 // r = co*.75 + q*.25
02046             VertDataCopy(r, co);
02047             VertDataMulN(r, 0.75f);
02048             VertDataMulN(q, 0.25f);
02049             VertDataAdd(r, q);
02050 
02051                 // nCo = nCo  + (r-nCo)*avgSharpness
02052             VertDataSub(r, nCo);
02053             VertDataMulN(r, avgSharpness);
02054             VertDataAdd(nCo, r);
02055         }
02056 
02057         // vert flags cleared later
02058     }
02059 
02060     if (ss->useAgeCounts) {
02061         for (i=0; i<numEffectedV; i++) {
02062             CCGVert *v = effectedV[i];
02063             byte *userData = ccgSubSurf_getVertUserData(ss, v);
02064             *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
02065         }
02066 
02067         for (i=0; i<numEffectedE; i++) {
02068             CCGEdge *e = effectedE[i];
02069             byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
02070             *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
02071         }
02072 
02073         for (i=0; i<numEffectedF; i++) {
02074             CCGFace *f = effectedF[i];
02075             byte *userData = ccgSubSurf_getFaceUserData(ss, f);
02076             *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
02077         }
02078     }
02079 
02080     for (i=0; i<numEffectedE; i++) {
02081         CCGEdge *e = effectedE[i];
02082         VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
02083         VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
02084     }
02085     for (i=0; i<numEffectedF; i++) {
02086         CCGFace *f = effectedF[i];
02087         for (S=0; S<f->numVerts; S++) {
02088             CCGEdge *e = FACE_getEdges(f)[S];
02089             CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
02090 
02091             VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
02092             VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
02093             VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
02094             VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
02095 
02096             VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
02097             VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
02098         }
02099     }
02100 
02101     for (curLvl=1; curLvl<subdivLevels; curLvl++) {
02102         ccgSubSurf__calcSubdivLevel(ss,
02103             effectedV, effectedE, effectedF,
02104             numEffectedV, numEffectedE, numEffectedF, curLvl);
02105     }
02106 
02107     if (ss->calcVertNormals)
02108         ccgSubSurf__calcVertNormals(ss,
02109             effectedV, effectedE, effectedF,
02110             numEffectedV, numEffectedE, numEffectedF);
02111 
02112     for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
02113         CCGVert *v = effectedV[ptrIdx];
02114         v->flags = 0;
02115     }
02116     for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
02117         CCGEdge *e = effectedE[ptrIdx];
02118         e->flags = 0;
02119     }
02120 
02121     MEM_freeN(effectedF);
02122     MEM_freeN(effectedE);
02123     MEM_freeN(effectedV);
02124 }
02125 
02126 static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
02127 {
02128     CCGFace **array;
02129     int i, num;
02130 
02131     if(!*faces) {
02132         array = MEM_mallocN(sizeof(*array)*ss->fMap->numEntries, "CCGSubsurf allFaces");
02133         num = 0;
02134         for (i=0; i<ss->fMap->curSize; i++) {
02135             CCGFace *f = (CCGFace*) ss->fMap->buckets[i];
02136 
02137             for (; f; f = f->next)
02138                 array[num++] = f;
02139         }
02140 
02141         *faces = array;
02142         *numFaces = num;
02143         *freeFaces= 1;
02144     }
02145     else
02146         *freeFaces= 0;
02147 }
02148 
02149 static void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges)
02150 {
02151     CCGVert **arrayV;
02152     CCGEdge **arrayE;
02153     int numV, numE, i, j;
02154 
02155     arrayV = MEM_mallocN(sizeof(*arrayV)*ss->vMap->numEntries, "CCGSubsurf arrayV");
02156     arrayE = MEM_mallocN(sizeof(*arrayE)*ss->eMap->numEntries, "CCGSubsurf arrayV");
02157     numV = numE = 0;
02158 
02159     for (i=0; i<numFaces; i++) {
02160         CCGFace *f = faces[i];
02161         f->flags |= Face_eEffected;
02162     }
02163 
02164     for (i=0; i<ss->vMap->curSize; i++) {
02165         CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
02166 
02167         for (; v; v = v->next) {
02168             for(j=0; j<v->numFaces; j++)
02169                 if(!(v->faces[j]->flags & Face_eEffected))
02170                     break;
02171             
02172             if(j == v->numFaces) {
02173                 arrayV[numV++] = v;
02174                 v->flags |= Vert_eEffected;
02175             }
02176         }
02177     }
02178 
02179     for (i=0; i<ss->eMap->curSize; i++) {
02180         CCGEdge *e = (CCGEdge*) ss->eMap->buckets[i];
02181 
02182         for (; e; e = e->next) {
02183             for(j=0; j<e->numFaces; j++)
02184                 if(!(e->faces[j]->flags & Face_eEffected))
02185                     break;
02186             
02187             if(j == e->numFaces) {
02188                 e->flags |= Edge_eEffected;
02189                 arrayE[numE++] = e;
02190             }
02191         }
02192     }
02193 
02194     *verts = arrayV;
02195     *numVerts = numV;
02196     *edges = arrayE;
02197     *numEdges = numE;
02198 }
02199 
02200 /* copy face grid coordinates to other places */
02201 CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
02202 {
02203     int i, S, x, gridSize, cornerIdx, subdivLevels;
02204     int vertDataSize = ss->meshIFC.vertDataSize, freeF;
02205 
02206     subdivLevels = ss->subdivLevels;
02207     lvl = (lvl)? lvl: subdivLevels;
02208     gridSize = 1 + (1<<(lvl-1));
02209     cornerIdx = gridSize-1;
02210 
02211     ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
02212 
02213     for (i=0; i<numEffectedF; i++) {
02214         CCGFace *f = effectedF[i];
02215 
02216         for (S=0; S<f->numVerts; S++) {
02217             CCGEdge *e = FACE_getEdges(f)[S];
02218             CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
02219 
02220             VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
02221             VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
02222 
02223             for (x=0; x<gridSize; x++)
02224                 VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
02225 
02226             for (x=0; x<gridSize; x++) {
02227                 int eI = gridSize-1-x;
02228                 VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
02229                 VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
02230             }
02231         }
02232     }
02233 
02234     if(freeF) MEM_freeN(effectedF);
02235 
02236     return eCCGError_None;
02237 }
02238 
02239 /* copy other places to face grid coordinates */
02240 CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
02241 {
02242     int i, S, x, gridSize, cornerIdx, subdivLevels;
02243     int vertDataSize = ss->meshIFC.vertDataSize, freeF;
02244 
02245     subdivLevels = ss->subdivLevels;
02246     lvl = (lvl)? lvl: subdivLevels;
02247     gridSize = 1 + (1<<(lvl-1));
02248     cornerIdx = gridSize-1;
02249 
02250     ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
02251 
02252     for (i=0; i<numEffectedF; i++) {
02253         CCGFace *f = effectedF[i];
02254 
02255         for (S=0; S<f->numVerts; S++) {
02256             int prevS = (S+f->numVerts-1)%f->numVerts;
02257             CCGEdge *e = FACE_getEdges(f)[S];
02258             CCGEdge *prevE = FACE_getEdges(f)[prevS];
02259 
02260             for (x=0; x<gridSize; x++) {
02261                 int eI = gridSize-1-x;
02262                 VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
02263                 VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
02264             }
02265 
02266             for (x=1; x<gridSize-1; x++) {
02267                 VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
02268                 VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
02269             }
02270 
02271             VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
02272             VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
02273         }
02274     }
02275 
02276     if(freeF) MEM_freeN(effectedF);
02277 
02278     return eCCGError_None;
02279 }
02280 
02281 /* stitch together face grids, averaging coordinates at edges
02282    and vertices, for multires displacements */
02283 CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
02284 {
02285     CCGVert **effectedV;
02286     CCGEdge **effectedE;
02287     int numEffectedV, numEffectedE, freeF;
02288     int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
02289     int vertDataSize = ss->meshIFC.vertDataSize;
02290 
02291     subdivLevels = ss->subdivLevels;
02292     lvl = (lvl)? lvl: subdivLevels;
02293     gridSize = 1 + (1<<(lvl-1));
02294     edgeSize = 1 + (1<<lvl);
02295     cornerIdx = gridSize-1;
02296 
02297     ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
02298     ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
02299         &effectedV, &numEffectedV, &effectedE, &numEffectedE);
02300 
02301     /* zero */
02302     for (i=0; i<numEffectedV; i++) {
02303         CCGVert *v = effectedV[i];
02304         if(v->numFaces)
02305             VertDataZero(VERT_getCo(v, lvl));
02306     }
02307 
02308     for (i=0; i<numEffectedE; i++) {
02309         CCGEdge *e = effectedE[i];
02310 
02311         if(e->numFaces)
02312             for (x=0; x<edgeSize; x++)
02313                 VertDataZero(EDGE_getCo(e, lvl, x));
02314     }
02315 
02316     /* add */
02317     for (i=0; i<numEffectedF; i++) {
02318         CCGFace *f = effectedF[i];
02319 
02320         VertDataZero(FACE_getCenterData(f));
02321 
02322         for (S=0; S<f->numVerts; S++)
02323             for (x=0; x<gridSize; x++)
02324                 VertDataZero(FACE_getIECo(f, lvl, S, x));
02325 
02326         for (S=0; S<f->numVerts; S++) {
02327             int prevS = (S+f->numVerts-1)%f->numVerts;
02328             CCGEdge *e = FACE_getEdges(f)[S];
02329             CCGEdge *prevE = FACE_getEdges(f)[prevS];
02330 
02331             VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
02332             if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
02333                 VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
02334 
02335             for (x=1; x<gridSize-1; x++) {
02336                 VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
02337                 VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
02338             }
02339 
02340             for (x=0; x<gridSize-1; x++) {
02341                 int eI = gridSize-1-x;
02342                 if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
02343                     VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
02344                 if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
02345                     if(x != 0)
02346                         VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
02347             }
02348         }
02349     }
02350 
02351     /* average */
02352     for (i=0; i<numEffectedV; i++) {
02353         CCGVert *v = effectedV[i];
02354         if(v->numFaces)
02355             VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces);
02356     }
02357 
02358     for (i=0; i<numEffectedE; i++) {
02359         CCGEdge *e = effectedE[i];
02360 
02361         VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl));
02362         VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl));
02363 
02364         if(e->numFaces)
02365             for (x=1; x<edgeSize-1; x++)
02366                 VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces);
02367     }
02368 
02369     /* copy */
02370     for (i=0; i<numEffectedF; i++) {
02371         CCGFace *f = effectedF[i];
02372 
02373         VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
02374 
02375         for (S=0; S<f->numVerts; S++)
02376             for (x=1; x<gridSize-1; x++)
02377                 VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);
02378 
02379         for (S=0; S<f->numVerts; S++) {
02380             int prevS = (S+f->numVerts-1)%f->numVerts;
02381             CCGEdge *e = FACE_getEdges(f)[S];
02382             CCGEdge *prevE = FACE_getEdges(f)[prevS];
02383 
02384             VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
02385             VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
02386 
02387             for (x=1; x<gridSize-1; x++) {
02388                 VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
02389                 VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
02390             }
02391 
02392             for (x=0; x<gridSize-1; x++) {
02393                 int eI = gridSize-1-x;
02394                 VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
02395                 VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
02396             }
02397 
02398             VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f));
02399             VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0));
02400         }
02401     }
02402 
02403     for (i=0; i<numEffectedV; i++)
02404         effectedV[i]->flags = 0;
02405     for (i=0; i<numEffectedE; i++)
02406         effectedE[i]->flags = 0;
02407     for (i=0; i<numEffectedF; i++)
02408         effectedF[i]->flags = 0;
02409 
02410     MEM_freeN(effectedE);
02411     MEM_freeN(effectedV);
02412     if(freeF) MEM_freeN(effectedF);
02413 
02414     return eCCGError_None;
02415 }
02416 
02417 /* update normals for specified faces */
02418 CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) {
02419     CCGVert **effectedV;
02420     CCGEdge **effectedE;
02421     int i, numEffectedV, numEffectedE, freeF;
02422 
02423     ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
02424     ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
02425         &effectedV, &numEffectedV, &effectedE, &numEffectedE);
02426 
02427     if (ss->calcVertNormals)
02428         ccgSubSurf__calcVertNormals(ss,
02429             effectedV, effectedE, effectedF,
02430             numEffectedV, numEffectedE, numEffectedF);
02431 
02432     for (i=0; i<numEffectedV; i++)
02433         effectedV[i]->flags = 0;
02434     for (i=0; i<numEffectedE; i++)
02435         effectedE[i]->flags = 0;
02436     for (i=0; i<numEffectedF; i++)
02437         effectedF[i]->flags = 0;
02438 
02439     MEM_freeN(effectedE);
02440     MEM_freeN(effectedV);
02441     if(freeF) MEM_freeN(effectedF);
02442 
02443     return eCCGError_None;
02444 }
02445 
02446 /* compute subdivision levels from a given starting point, used by
02447    multires subdivide/propagate, by filling in coordinates at a
02448    certain level, and then subdividing that up to the highest level */
02449 CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
02450 {
02451     CCGVert **effectedV;
02452     CCGEdge **effectedE;
02453     int numEffectedV, numEffectedE, freeF, i;
02454     int curLvl, subdivLevels = ss->subdivLevels;
02455 
02456     ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
02457     ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
02458         &effectedV, &numEffectedV, &effectedE, &numEffectedE);
02459 
02460     for (curLvl=lvl; curLvl<subdivLevels; curLvl++) {
02461         ccgSubSurf__calcSubdivLevel(ss,
02462             effectedV, effectedE, effectedF,
02463             numEffectedV, numEffectedE, numEffectedF, curLvl);
02464     }
02465 
02466     for (i=0; i<numEffectedV; i++)
02467         effectedV[i]->flags = 0;
02468     for (i=0; i<numEffectedE; i++)
02469         effectedE[i]->flags = 0;
02470     for (i=0; i<numEffectedF; i++)
02471         effectedF[i]->flags = 0;
02472 
02473     MEM_freeN(effectedE);
02474     MEM_freeN(effectedV);
02475     if(freeF) MEM_freeN(effectedF);
02476 
02477     return eCCGError_None;
02478 }
02479 
02480 #undef VERT_getCo
02481 #undef EDGE_getCo
02482 #undef FACE_getIECo
02483 #undef FACE_getIFCo
02484 
02485 /*** External API accessor functions ***/
02486 
02487 int ccgSubSurf_getNumVerts(const CCGSubSurf *ss) {
02488     return ss->vMap->numEntries;
02489 }
02490 int ccgSubSurf_getNumEdges(const CCGSubSurf *ss) {
02491     return ss->eMap->numEntries;
02492 }
02493 int ccgSubSurf_getNumFaces(const CCGSubSurf *ss) {
02494     return ss->fMap->numEntries;
02495 }
02496 
02497 CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) {
02498     return (CCGVert*) _ehash_lookup(ss->vMap, v);
02499 }
02500 CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) {
02501     return (CCGEdge*) _ehash_lookup(ss->eMap, e);
02502 }
02503 CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) {
02504     return (CCGFace*) _ehash_lookup(ss->fMap, f);
02505 }
02506 
02507 int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss) {
02508     return ss->subdivLevels;
02509 }
02510 int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss) {
02511     return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
02512 }
02513 int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level) {
02514     if (level<1 || level>ss->subdivLevels) {
02515         return -1;
02516     } else {
02517         return 1 + (1<<level);
02518     }
02519 }
02520 int ccgSubSurf_getGridSize(const CCGSubSurf *ss) {
02521     return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
02522 }
02523 int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level) {
02524     if (level<1 || level>ss->subdivLevels) {
02525         return -1;
02526     } else {
02527         return 1 + (1<<(level-1));
02528     }
02529 }
02530 
02531 /* Vert accessors */
02532 
02533 CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v) {
02534     return v->vHDL;
02535 }
02536 int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) {
02537     if (ss->useAgeCounts) {
02538         byte *userData = ccgSubSurf_getVertUserData(ss, v);
02539         return ss->currentAge - *((int*) &userData[ss->vertUserAgeOffset]);
02540     } else {
02541         return 0;
02542     }
02543 }
02544 void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) {
02545     return VERT_getLevelData(v) + ss->meshIFC.vertDataSize*(ss->subdivLevels+1);
02546 }
02547 int ccgSubSurf_getVertNumFaces(CCGVert *v) {
02548     return v->numFaces;
02549 }
02550 CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index) {
02551     if (index<0 || index>=v->numFaces) {
02552         return NULL;
02553     } else {
02554         return v->faces[index];
02555     }
02556 }
02557 int ccgSubSurf_getVertNumEdges(CCGVert *v) {
02558     return v->numEdges;
02559 }
02560 CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index) {
02561     if (index<0 || index>=v->numEdges) {
02562         return NULL;
02563     } else {
02564         return v->edges[index];
02565     }
02566 }
02567 void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) {
02568     return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
02569 }
02570 void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) {
02571     if (level<0 || level>ss->subdivLevels) {
02572         return NULL;
02573     } else {
02574         return _vert_getCo(v, level, ss->meshIFC.vertDataSize);
02575     }
02576 }
02577 
02578 /* Edge accessors */
02579 
02580 CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e) {
02581     return e->eHDL;
02582 }
02583 int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) {
02584     if (ss->useAgeCounts) {
02585         byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
02586         return ss->currentAge - *((int*) &userData[ss->edgeUserAgeOffset]);
02587     } else {
02588         return 0;
02589     }
02590 }
02591 void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) {
02592     return EDGE_getLevelData(e) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1);
02593 }
02594 int ccgSubSurf_getEdgeNumFaces(CCGEdge *e) {
02595     return e->numFaces;
02596 }
02597 CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index) {
02598     if (index<0 || index>=e->numFaces) {
02599         return NULL;
02600     } else {
02601         return e->faces[index];
02602     }
02603 }
02604 CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e) {
02605     return e->v0;
02606 }
02607 CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e) {
02608     return e->v1;
02609 }
02610 void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) {
02611     return ccgSubSurf_getEdgeData(ss, e, 0);
02612 }
02613 void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) {
02614     return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
02615 }
02616 void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) {
02617     if (level<0 || level>ss->subdivLevels) {
02618         return NULL;
02619     } else {
02620         return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
02621     }
02622 }
02623 float ccgSubSurf_getEdgeCrease(CCGEdge *e) {
02624     return e->crease;
02625 }
02626 
02627 /* Face accessors */
02628 
02629 CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGSubSurf *UNUSED(ss), CCGFace *f) {
02630     return f->fHDL;
02631 }
02632 int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) {
02633     if (ss->useAgeCounts) {
02634         byte *userData = ccgSubSurf_getFaceUserData(ss, f);
02635         return ss->currentAge - *((int*) &userData[ss->faceUserAgeOffset]);
02636     } else {
02637         return 0;
02638     }
02639 }
02640 void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) {
02641     int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
02642     return FACE_getCenterData(f) + ss->meshIFC.vertDataSize *(1 + f->numVerts*maxGridSize + f->numVerts*maxGridSize*maxGridSize);
02643 }
02644 int ccgSubSurf_getFaceNumVerts(CCGFace *f) {
02645     return f->numVerts;
02646 }
02647 CCGVert *ccgSubSurf_getFaceVert(CCGSubSurf *UNUSED(ss), CCGFace *f, int index) {
02648     if (index<0 || index>=f->numVerts) {
02649         return NULL;
02650     } else {
02651         return FACE_getVerts(f)[index];
02652     }
02653 }
02654 CCGEdge *ccgSubSurf_getFaceEdge(CCGSubSurf *UNUSED(ss), CCGFace *f, int index) {
02655     if (index<0 || index>=f->numVerts) {
02656         return NULL;
02657     } else {
02658         return FACE_getEdges(f)[index];
02659     }
02660 }
02661 int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e) {
02662     int i;
02663 
02664     for (i=0; i<f->numVerts; i++)
02665         if (FACE_getEdges(f)[i]==e)
02666             return i;
02667 
02668     return -1;
02669 }
02670 void *ccgSubSurf_getFaceCenterData(CCGFace *f) {
02671     return FACE_getCenterData(f);
02672 }
02673 void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
02674     return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
02675 }
02676 void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) {
02677     return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
02678 }
02679 void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
02680     return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
02681 }
02682 void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) {
02683     return _face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
02684 }
02685 
02686 /*** External API iterator functions ***/
02687 
02688 CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) {
02689     return (CCGVertIterator*) _ehashIterator_new(ss->vMap);
02690 }
02691 CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) {
02692     return (CCGEdgeIterator*) _ehashIterator_new(ss->eMap);
02693 }
02694 CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) {
02695     return (CCGFaceIterator*) _ehashIterator_new(ss->fMap);
02696 }
02697 
02698 CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) {
02699     return (CCGVert*) _ehashIterator_getCurrent((EHashIterator*) vi);
02700 }
02701 int ccgVertIterator_isStopped(CCGVertIterator *vi) {
02702     return _ehashIterator_isStopped((EHashIterator*) vi);
02703 }
02704 void ccgVertIterator_next(CCGVertIterator *vi) {
02705     _ehashIterator_next((EHashIterator*) vi); 
02706 }
02707 void ccgVertIterator_free(CCGVertIterator *vi) {
02708     _ehashIterator_free((EHashIterator*) vi);
02709 }
02710 
02711 CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) {
02712     return (CCGEdge*) _ehashIterator_getCurrent((EHashIterator*) vi);
02713 }
02714 int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) {
02715     return _ehashIterator_isStopped((EHashIterator*) vi);
02716 }
02717 void ccgEdgeIterator_next(CCGEdgeIterator *vi) {
02718     _ehashIterator_next((EHashIterator*) vi); 
02719 }
02720 void ccgEdgeIterator_free(CCGEdgeIterator *vi) {
02721     _ehashIterator_free((EHashIterator*) vi);
02722 }
02723 
02724 CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) {
02725     return (CCGFace*) _ehashIterator_getCurrent((EHashIterator*) vi);
02726 }
02727 int ccgFaceIterator_isStopped(CCGFaceIterator *vi) {
02728     return _ehashIterator_isStopped((EHashIterator*) vi);
02729 }
02730 void ccgFaceIterator_next(CCGFaceIterator *vi) {
02731     _ehashIterator_next((EHashIterator*) vi); 
02732 }
02733 void ccgFaceIterator_free(CCGFaceIterator *vi) {
02734     _ehashIterator_free((EHashIterator*) vi);
02735 }
02736 
02737 /*** Extern API final vert/edge/face interface ***/
02738 
02739 int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss) {
02740     int edgeSize = 1 + (1<<ss->subdivLevels);
02741     int gridSize = 1 + (1<<(ss->subdivLevels-1));
02742     int numFinalVerts = ss->vMap->numEntries + ss->eMap->numEntries*(edgeSize-2) + ss->fMap->numEntries + ss->numGrids*((gridSize-2) + ((gridSize-2)*(gridSize-2)));
02743     return numFinalVerts;
02744 }
02745 int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) {
02746     int edgeSize = 1 + (1<<ss->subdivLevels);
02747     int gridSize = 1 + (1<<(ss->subdivLevels-1));
02748     int numFinalEdges = ss->eMap->numEntries*(edgeSize-1) + ss->numGrids*((gridSize-1) + 2*((gridSize-2)*(gridSize-1)));
02749     return numFinalEdges;
02750 }
02751 int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss) {
02752     int gridSize = 1 + (1<<(ss->subdivLevels-1));
02753     int numFinalFaces = ss->numGrids*((gridSize-1)*(gridSize-1));
02754     return numFinalFaces;
02755 }