- fix warnings for gcc
[blender.git] / source / blender / blenkernel / intern / CCGSubSurf.c
1 /* $Id$ */
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6
7 #include "CCGSubSurf.h"
8
9 #define USE_CREASING
10
11 /***/
12
13 typedef unsigned char   byte;
14
15 /***/
16
17 static int kHashSizes[] = {
18         1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 
19         16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, 
20         4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459
21 };
22
23 typedef struct _EHEntry EHEntry;
24 struct _EHEntry {
25         EHEntry *next;
26         void *key;
27 };
28 typedef struct _EHash {
29         EHEntry **buckets;
30         int numEntries, curSize, curSizeIdx;
31
32         CCGAllocatorIFC allocatorIFC;
33         CCGAllocatorHDL allocator;
34 } EHash;
35
36 #define EHASH_alloc(eh, nb)                     ((eh)->allocatorIFC.alloc((eh)->allocator, nb))
37 #define EHASH_free(eh, ptr)                     ((eh)->allocatorIFC.free((eh)->allocator, ptr))
38
39 #define EHASH_hash(eh, item)    (((unsigned int) (item))%((unsigned int) (eh)->curSize))
40
41 static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
42         EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh));
43         eh->allocatorIFC = *allocatorIFC;
44         eh->allocator = allocator;
45         eh->numEntries = 0;
46         eh->curSizeIdx = 0;
47         while (kHashSizes[eh->curSizeIdx]<estimatedNumEntries)
48                 eh->curSizeIdx++;
49         eh->curSize = kHashSizes[eh->curSizeIdx];
50         eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
51         memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
52
53         return eh;
54 }
55 typedef void (*EHEntryFreeFP)(EHEntry *, void *);
56 static void _ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) {
57         int numBuckets = eh->curSize;
58
59         while (numBuckets--) {
60                 EHEntry *entry = eh->buckets[numBuckets];
61
62                 while (entry) {
63                         EHEntry *next = entry->next;
64
65                         freeEntry(entry, userData);
66
67                         entry = next;
68                 }
69         }
70
71         EHASH_free(eh, eh->buckets);
72         EHASH_free(eh, eh);
73 }
74
75 static void _ehash_insert(EHash *eh, EHEntry *entry) {
76         int numBuckets = eh->curSize;
77         int hash = EHASH_hash(eh, entry->key);
78         entry->next = eh->buckets[hash];
79         eh->buckets[hash] = entry;
80         eh->numEntries++;
81
82         if (eh->numEntries > (numBuckets*3)) {
83                 EHEntry **oldBuckets = eh->buckets;
84                 eh->curSize = kHashSizes[++eh->curSizeIdx];
85                 
86                 eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
87                 memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
88
89                 while (numBuckets--) {
90                         for (entry = oldBuckets[numBuckets]; entry;) {
91                                 EHEntry *next = entry->next;
92                                 
93                                 hash = EHASH_hash(eh, entry->key);
94                                 entry->next = eh->buckets[hash];
95                                 eh->buckets[hash] = entry;
96                                 
97                                 entry = next;
98                         }
99                 }
100
101                 EHASH_free(eh, oldBuckets);
102         }
103 }
104
105 static void *_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) {
106         int hash = EHASH_hash(eh, key);
107         void **prevp = (void**) &eh->buckets[hash];
108         EHEntry *entry;
109         
110         for (; (entry = *prevp); prevp = (void**) &entry->next) {
111                 if (entry->key==key) {
112                         *prevp_r = (void**) prevp;
113                         return entry;
114                 }
115         }
116         
117         return NULL;
118 }
119
120 static void *_ehash_lookup(EHash *eh, void *key) {
121         int hash = EHASH_hash(eh, key);
122         EHEntry *entry;
123         
124         for (entry = eh->buckets[hash]; entry; entry = entry->next)
125                 if (entry->key==key)
126                         break;
127         
128         return entry;
129 }
130
131 /**/
132
133 typedef struct _EHashIterator {
134         EHash *eh;
135         int curBucket;
136         EHEntry *curEntry;
137 } EHashIterator;
138
139 static EHashIterator *_ehashIterator_new(EHash *eh) {
140         EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi));
141         ehi->eh = eh;
142         ehi->curEntry = NULL;
143         ehi->curBucket = -1;
144         while (!ehi->curEntry) {
145                 ehi->curBucket++;
146                 if (ehi->curBucket==ehi->eh->curSize)
147                         break;
148                 ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
149         }
150         return ehi;
151 }
152 static void _ehashIterator_free(EHashIterator *ehi) {
153         EHASH_free(ehi->eh, ehi);
154 }
155
156 static void *_ehashIterator_getCurrent(EHashIterator *ehi) {
157         return ehi->curEntry;
158 }
159
160 static void _ehashIterator_next(EHashIterator *ehi) {
161         if (ehi->curEntry) {
162         ehi->curEntry = ehi->curEntry->next;
163                 while (!ehi->curEntry) {
164                         ehi->curBucket++;
165                         if (ehi->curBucket==ehi->eh->curSize)
166                                 break;
167                         ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
168                 }
169         }
170 }
171 static int _ehashIterator_isStopped(EHashIterator *ehi) {
172         return !ehi->curEntry;
173 }
174
175 /***/
176
177 static void *_stdAllocator_alloc(CCGAllocatorHDL a, int numBytes) {
178         return malloc(numBytes);
179 }
180 static void *_stdAllocator_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) {
181         return realloc(ptr, newSize);
182 }
183 static void _stdAllocator_free(CCGAllocatorHDL a, void *ptr) {
184         free(ptr);
185 }
186
187 static CCGAllocatorIFC *_getStandardAllocatorIFC(void) {
188         static CCGAllocatorIFC ifc;
189
190         ifc.alloc = _stdAllocator_alloc;
191         ifc.realloc = _stdAllocator_realloc;
192         ifc.free = _stdAllocator_free;
193         ifc.release = NULL;
194
195         return &ifc;
196 }
197
198 /***/
199
200 static int _edge_isBoundary(CCGEdge *e);
201
202 /***/
203
204 enum {
205         Vert_eEffected=         (1<<0),
206         Vert_eChanged=          (1<<1),
207 } VertFlags;
208 enum {
209         Edge_eEffected=         (1<<0),
210 } CCGEdgeFlags;
211 enum {
212         Face_eEffected=         (1<<0),
213 } FaceFlags;
214
215 struct _CCGVert {
216         CCGVert         *next;  /* EHData.next */
217         CCGVertHDL      vHDL;   /* EHData.key */
218
219         short numEdges, numFaces, flags, pad;
220
221         CCGEdge **edges;
222         CCGFace **faces;
223 //      byte *levelData;
224 //      byte *userData;
225 };
226 #define VERT_getLevelData(v)            ((byte*) &(v)[1])
227
228 struct _CCGEdge {
229         CCGEdge         *next;  /* EHData.next */
230         CCGEdgeHDL      eHDL;   /* EHData.key */
231
232         short numFaces, flags;
233
234         CCGVert *v0,*v1;
235         CCGFace **faces;
236
237 //      byte *levelData;
238 //      byte *userData;
239 };
240 #define EDGE_getLevelData(e)            ((byte*) &(e)[1])
241
242 struct _CCGFace {
243         CCGFace         *next;  /* EHData.next */
244         CCGFaceHDL      fHDL;   /* EHData.key */
245
246         short numVerts, flags, pad1, pad2;
247
248 //      CCGVert **verts;
249 //      CCGEdge **edges;
250 //      byte *centerData;
251 //      byte **gridData;
252 //      byte *userData;
253 };
254 #define FACE_getVerts(f)                ((CCGVert**) &(f)[1])
255 #define FACE_getEdges(f)                ((CCGEdge**) &(FACE_getVerts(f)[(f)->numVerts]))
256 #define FACE_getCenterData(f)   ((byte*) &(FACE_getEdges(f)[(f)->numVerts]))
257
258 typedef enum {
259         eSyncState_None = 0,
260         eSyncState_Vert,
261         eSyncState_Edge,
262         eSyncState_Face,
263         eSyncState_Partial,
264 } SyncState;
265
266 struct _CCGSubSurf {
267         EHash *vMap;    /* map of CCGVertHDL -> Vert */
268         EHash *eMap;    /* map of CCGEdgeHDL -> Edge */
269         EHash *fMap;    /* map of CCGFaceHDL -> Face */
270
271         CCGMeshIFC meshIFC;
272         void *meshData;
273
274         CCGAllocatorIFC allocatorIFC;
275         CCGAllocatorHDL allocator;
276
277         int subdivLevels;
278         int numGrids;
279         int allowEdgeCreation;
280
281         void *q, *r;
282
283                 // data for age'ing (to debug sync)
284         int currentAge;
285         int useAgeCounts;
286         int vertUserAgeOffset;
287         int edgeUserAgeOffset;
288         int faceUserAgeOffset;
289
290                 // data used during syncing
291         SyncState syncState;
292
293         EHash *oldVMap, *oldEMap, *oldFMap;
294         int lenTempArrays;
295         CCGVert **tempVerts;
296         CCGEdge **tempEdges;
297 };
298
299 #define CCGSUBSURF_alloc(ss, nb)                        ((ss)->allocatorIFC.alloc((ss)->allocator, nb))
300 #define CCGSUBSURF_realloc(ss, ptr, nb, ob)     ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob))
301 #define CCGSUBSURF_free(ss, ptr)                        ((ss)->allocatorIFC.free((ss)->allocator, ptr))
302
303 /***/
304
305 static CCGVert *_vert_new(CCGVertHDL vHDL, int levels, int dataSize, CCGSubSurf *ss) {
306         CCGVert *v = CCGSUBSURF_alloc(ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * (ss->subdivLevels+1) + ss->meshIFC.vertUserSize);
307         byte *userData;
308
309         v->vHDL = vHDL;
310         v->edges = NULL;
311         v->faces = NULL;
312         v->numEdges = v->numFaces = 0;
313         v->flags = 0;
314
315         userData = ccgSubSurf_getVertUserData(ss, v);
316         memset(userData, 0, ss->meshIFC.vertUserSize);
317         if (ss->useAgeCounts) *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
318
319         return v;
320 }
321 static void _vert_remEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
322         int i;
323         for (i=0; i<v->numEdges; i++) {
324                 if (v->edges[i]==e) {
325                         v->edges[i] = v->edges[--v->numEdges];
326                         break;
327                 }
328         }
329 }
330 static void _vert_remFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
331         int i;
332         for (i=0; i<v->numFaces; i++) {
333                 if (v->faces[i]==f) {
334                         v->faces[i] = v->faces[--v->numFaces];
335                         break;
336                 }
337         }
338 }
339 static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
340         v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges+1)*sizeof(*v->edges), v->numEdges*sizeof(*v->edges));
341         v->edges[v->numEdges++] = e;
342 }
343 static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
344         v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces+1)*sizeof(*v->faces), v->numFaces*sizeof(*v->faces));
345         v->faces[v->numFaces++] = f;
346 }
347 static CCGEdge *_vert_findEdgeTo(CCGVert *v, CCGVert *vQ) {
348         int i;
349         for (i=0; i<v->numEdges; i++) {
350                 CCGEdge *e = v->edges[v->numEdges-1-i]; // XXX, note reverse
351                 if (    (e->v0==v && e->v1==vQ) ||
352                                 (e->v1==v && e->v0==vQ))
353                         return e;
354         }
355         return 0;
356 }
357 static int _vert_isBoundary(CCGVert *v) {
358         int i;
359         for (i=0; i<v->numEdges; i++)
360                 if (_edge_isBoundary(v->edges[i]))
361                         return 1;
362         return 0;
363 }
364
365 static void *_vert_getCo(CCGVert *v, int lvl, int dataSize) {
366         return &VERT_getLevelData(v)[lvl*dataSize];
367 }
368
369 static void _vert_free(CCGVert *v, CCGSubSurf *ss) {
370         CCGSUBSURF_free(ss, v->edges);
371         CCGSUBSURF_free(ss, v->faces);
372         CCGSUBSURF_free(ss, v);
373 }
374
375 /***/
376
377 static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, int levels, int dataSize, CCGSubSurf *ss) {
378         CCGEdge *e = CCGSUBSURF_alloc(ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1) + ss->meshIFC.edgeUserSize);
379         byte *userData;
380
381         e->eHDL = eHDL;
382         e->v0 = v0;
383         e->v1 = v1;
384         e->faces = NULL;
385         e->numFaces = 0;
386         e->flags = 0;
387         _vert_addEdge(v0, e, ss);
388         _vert_addEdge(v1, e, ss);
389
390         userData = ccgSubSurf_getEdgeUserData(ss, e);
391         memset(userData, 0, ss->meshIFC.edgeUserSize);
392         if (ss->useAgeCounts) *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
393
394         return e;
395 }
396 static void _edge_remFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
397         int i;
398         for (i=0; i<e->numFaces; i++) {
399                 if (e->faces[i]==f) {
400                         e->faces[i] = e->faces[--e->numFaces];
401                         break;
402                 }
403         }
404 }
405 static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
406         e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces+1)*sizeof(*e->faces), e->numFaces*sizeof(*e->faces));
407         e->faces[e->numFaces++] = f;
408 }
409 static int _edge_isBoundary(CCGEdge *e) {
410         return e->numFaces<2;
411 }
412
413 static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) {
414         if (vQ==e->v0) {
415                 return e->v1;
416         } else {
417                 return e->v0;
418         }
419 }
420
421 static void *_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) {
422         int levelBase = lvl + (1<<lvl) - 1;
423         return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
424 }
425 static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) {
426         int levelBase = lvl + (1<<lvl) - 1;
427         if (v==e->v0) {
428                 return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
429         } else {
430                 return &EDGE_getLevelData(e)[dataSize*(levelBase + (1<<lvl) - x)];              
431         }
432 }
433
434 static void _edge_free(CCGEdge *e, CCGSubSurf *ss) {
435         CCGSUBSURF_free(ss, e->faces);
436         CCGSUBSURF_free(ss, e);
437 }
438 static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) {
439         _vert_remEdge(e->v0, e, ss);
440         _vert_remEdge(e->v1, e, ss);
441         e->v0->flags |= Vert_eEffected;
442         e->v1->flags |= Vert_eEffected;
443         _edge_free(e, ss);
444 }
445
446 #ifdef USE_CREASING
447 static float EDGE_getSharpness(CCGEdge *e, int lvl, CCGSubSurf *ss) {
448         float f,sharpness = f=(((float*) ccgSubSurf_getEdgeUserData(ss, e))[1]);
449         while ((sharpness>1.0) && lvl--)
450                 sharpness -= 1.0;
451         return sharpness;
452 }
453 #endif
454
455 /***/
456
457 static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, int levels, int dataSize, CCGSubSurf *ss) {
458         int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
459         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);
460         byte *userData;
461         int i;
462
463         f->numVerts = numVerts;
464         f->fHDL = fHDL;
465         f->flags = 0;
466
467         for (i=0; i<numVerts; i++) {
468                 FACE_getVerts(f)[i] = verts[i];
469                 FACE_getEdges(f)[i] = edges[i];
470                 _vert_addFace(verts[i], f, ss);
471                 _edge_addFace(edges[i], f, ss);
472         }
473
474         userData = ccgSubSurf_getFaceUserData(ss, f);
475         memset(userData, 0, ss->meshIFC.faceUserSize);
476         if (ss->useAgeCounts) *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
477
478         return f;
479 }
480
481 static void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) {
482         int maxGridSize = 1 + (1<<(levels-1));
483         int spacing = 1<<(levels-lvl);
484         byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
485         return &gridBase[dataSize*x*spacing];
486 }
487 static void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) {
488         int maxGridSize = 1 + (1<<(levels-1));
489         int spacing = 1<<(levels-lvl);
490         byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
491         return &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing)];
492 }
493 static int _face_getVertIndex(CCGFace *f, CCGVert *v) {
494         int i;
495         for (i=0; i<f->numVerts; i++)
496                 if (FACE_getVerts(f)[i]==v)
497                         return i;
498         return -1;
499 }
500 static void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize) {
501         int maxGridSize = 1 + (1<<(levels-1));
502         int spacing = 1<<(levels-lvl);
503         int S, x, y, cx, cy;
504
505         for (S=0; S<f->numVerts; S++)
506                 if (FACE_getEdges(f)[S]==e)
507                         break;
508
509         eX = eX*spacing;
510         eY = eY*spacing;
511         if (e->v0!=FACE_getVerts(f)[S]) {
512                 eX = (maxGridSize*2 - 1)-1 - eX;
513         }
514         y = maxGridSize - 1 - eX;
515         x = maxGridSize - 1 - eY;
516         if (x<0) {
517                 S = (S+f->numVerts-1)%f->numVerts;
518                 cx = y;
519                 cy = -x;
520         } else if (y<0) {
521                 S = (S+1)%f->numVerts;
522                 cx = -y;
523                 cy = x;
524         } else {
525                 cx = x;
526                 cy = y;
527         }
528         return _face_getIFCo(f, levels, S, cx, cy, levels, dataSize);
529 }
530
531 static void _face_free(CCGFace *f, CCGSubSurf *ss) {
532         CCGSUBSURF_free(ss, f);
533 }
534 static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) {
535         int j;
536         for (j=0; j<f->numVerts; j++) {
537                 _vert_remFace(FACE_getVerts(f)[j], f, ss);
538                 _edge_remFace(FACE_getEdges(f)[j], f, ss);
539                 FACE_getVerts(f)[j]->flags |= Vert_eEffected;
540         }
541         _face_free(f, ss);
542 }
543
544 /***/
545
546 CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, CCGMeshHDL meshData, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
547         if (!allocatorIFC) {
548                 allocatorIFC = _getStandardAllocatorIFC();
549                 allocator = NULL;
550         }
551
552         if (subdivLevels<1) {
553                 return NULL;
554         } else {
555                 CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
556
557                 ss->allocatorIFC = *allocatorIFC;
558                 ss->allocator = allocator;
559
560                 ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
561                 ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
562                 ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
563
564                 ss->meshIFC = *ifc;
565                 ss->meshData = meshData;
566
567                 ss->subdivLevels = subdivLevels;
568                 ss->numGrids = 0;
569                 ss->allowEdgeCreation = 0;
570
571                 ss->useAgeCounts = 0;
572                 ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
573
574                 ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
575                 ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
576
577                 ss->currentAge = 0;
578
579                 ss->syncState = eSyncState_None;
580
581                 ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
582                 ss->lenTempArrays = 0;
583                 ss->tempVerts = NULL;
584                 ss->tempEdges = NULL;   
585
586                 return ss;
587         }
588 }
589
590 void ccgSubSurf_free(CCGSubSurf *ss) {
591         CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
592         CCGAllocatorHDL allocator = ss->allocator;
593
594         if (ss->syncState) {
595                 _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss);
596                 _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss);
597                 _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
598
599                 CCGSUBSURF_free(ss, ss->tempVerts);
600                 CCGSUBSURF_free(ss, ss->tempEdges);
601         }
602
603         CCGSUBSURF_free(ss, ss->r);
604         CCGSUBSURF_free(ss, ss->q);
605
606         _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
607         _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
608         _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
609
610         CCGSUBSURF_free(ss, ss);
611
612         if (allocatorIFC.release) {
613                 allocatorIFC.release(allocator);
614         }
615 }
616
617 CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation) {
618         ss->allowEdgeCreation = !!allowEdgeCreation;
619
620         return eCCGError_None;
621 }
622
623 CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) {
624         if (subdivisionLevels<=0) {
625                 return eCCGError_InvalidValue;
626         } else if (subdivisionLevels!=ss->subdivLevels) {
627                 ss->numGrids = 0;
628                 ss->subdivLevels = subdivisionLevels;
629                 _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
630                 _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
631                 _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
632                 ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
633                 ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
634                 ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
635         }
636
637         return eCCGError_None;
638 }
639
640 CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) {
641         if (useAgeCounts) {
642                 if (    (vertUserOffset+4>ss->meshIFC.vertUserSize) ||
643                                 (edgeUserOffset+4>ss->meshIFC.edgeUserSize) ||
644                                 (faceUserOffset+4>ss->meshIFC.faceUserSize)) {
645                         return eCCGError_InvalidValue;
646                 }  else {
647                         ss->useAgeCounts = 1;
648                         ss->vertUserAgeOffset = vertUserOffset;
649                         ss->edgeUserAgeOffset = edgeUserOffset;
650                         ss->faceUserAgeOffset = faceUserOffset;
651                 }
652         } else {
653                 ss->useAgeCounts = 0;
654                 ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
655         }
656
657         return eCCGError_None;
658 }
659
660 /***/
661
662 CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) {
663         if (ss->syncState!=eSyncState_None) {
664                 return eCCGError_InvalidSyncState;
665         }
666
667         ss->currentAge++;
668
669         ss->oldVMap = ss->vMap; 
670         ss->oldEMap = ss->eMap; 
671         ss->oldFMap = ss->fMap;
672
673         ss->vMap = _ehash_new(ss->oldVMap->numEntries, &ss->allocatorIFC, ss->allocator);
674         ss->eMap = _ehash_new(ss->oldFMap->numEntries, &ss->allocatorIFC, ss->allocator);
675         ss->fMap = _ehash_new(ss->oldEMap->numEntries, &ss->allocatorIFC, ss->allocator);
676
677         ss->numGrids = 0;
678
679         ss->lenTempArrays = 12;
680         ss->tempVerts = CCGSUBSURF_alloc(ss, sizeof(*ss->tempVerts)*ss->lenTempArrays);
681         ss->tempEdges = CCGSUBSURF_alloc(ss, sizeof(*ss->tempEdges)*ss->lenTempArrays);
682
683         ss->syncState = eSyncState_Vert;
684
685         return eCCGError_None;
686 }
687
688 CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) {
689         if (ss->syncState!=eSyncState_None) {
690                 return eCCGError_InvalidSyncState;
691         }
692
693         ss->currentAge++;
694
695         ss->syncState = eSyncState_Partial;
696
697         return eCCGError_None;
698 }
699
700 CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) {
701         if (ss->syncState!=eSyncState_Partial) {
702                 return eCCGError_InvalidSyncState;
703         } else {
704                 void **prevp;
705                 CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
706
707                 if (!v || v->numFaces || v->numEdges) {
708                         return eCCGError_InvalidValue;
709                 } else {
710                         *prevp = v->next;
711                         _vert_free(v, ss);
712                 }
713         }
714
715         return eCCGError_None;
716 }
717
718 CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) {
719         if (ss->syncState!=eSyncState_Partial) {
720                 return eCCGError_InvalidSyncState;
721         } else {
722                 void **prevp;
723                 CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
724
725                 if (!e || e->numFaces) {
726                         return eCCGError_InvalidValue;
727                 } else {
728                         *prevp = e->next;
729                         _edge_unlinkMarkAndFree(e, ss);
730                 }
731         }
732
733         return eCCGError_None;
734 }
735
736 CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) {
737         if (ss->syncState!=eSyncState_Partial) {
738                 return eCCGError_InvalidSyncState;
739         } else {
740                 void **prevp;
741                 CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
742
743                 if (!f) {
744                         return eCCGError_InvalidValue;
745                 } else {
746                         *prevp = f->next;
747                         _face_unlinkMarkAndFree(f, ss);
748                 }
749         }
750
751         return eCCGError_None;
752 }
753
754 CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData) {
755         void **prevp;
756         CCGVert *v;
757         
758         if (ss->syncState==eSyncState_Partial) {
759                 v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
760                 if (!v) {
761                         v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
762                         ss->meshIFC.vertDataCopy(ss->meshData, _vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
763                         _ehash_insert(ss->vMap, (EHEntry*) v);
764                         v->flags = Vert_eEffected;
765                 } else if (!ss->meshIFC.vertDataEqual(ss->meshData, vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize))) {
766                         int i, j;
767
768                         ss->meshIFC.vertDataCopy(ss->meshData, _vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
769                         v->flags = Vert_eEffected;
770
771                         for (i=0; i<v->numEdges; i++) {
772                                 CCGEdge *e = v->edges[i];
773                                 e->v0->flags |= Vert_eEffected;
774                                 e->v1->flags |= Vert_eEffected;
775                         }
776                         for (i=0; i<v->numFaces; i++) {
777                                 CCGFace *f = v->faces[i];
778                                 for (j=0; j<f->numVerts; j++) {
779                                         FACE_getVerts(f)[j]->flags |= Vert_eEffected;
780                                 }
781                         }
782                 }
783         } else {
784                 if (ss->syncState!=eSyncState_Vert) { 
785                         return eCCGError_InvalidSyncState;
786                 }
787
788                 v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
789                 if (!v) {
790                         v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
791                         ss->meshIFC.vertDataCopy(ss->meshData, _vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
792                         _ehash_insert(ss->vMap, (EHEntry*) v);
793                         v->flags = Vert_eEffected;
794                 } else if (!ss->meshIFC.vertDataEqual(ss->meshData, vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize))) {
795                         *prevp = v->next;
796                         _ehash_insert(ss->vMap, (EHEntry*) v);
797                         ss->meshIFC.vertDataCopy(ss->meshData, _vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
798                         v->flags = Vert_eEffected|Vert_eChanged;
799                 } else {
800                         *prevp = v->next;
801                         _ehash_insert(ss->vMap, (EHEntry*) v);
802                         v->flags = 0;
803                 }
804         }
805
806         return eCCGError_None;
807 }
808
809 CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1) {
810         void **prevp;
811         CCGEdge *e, *eNew;
812
813         if (ss->syncState==eSyncState_Partial) {
814                 e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
815                 if (!e || ((e->v0->vHDL!=e_vHDL0) || (e->v1->vHDL!=e_vHDL1))) {
816                         CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
817                         CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
818
819                         eNew = _edge_new(eHDL, v0, v1, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
820
821                         if (e) {
822                                 *prevp = eNew;
823                                 eNew->next = e->next;
824
825                                 _edge_unlinkMarkAndFree(e, ss);
826                         } else {
827                                 _ehash_insert(ss->eMap, (EHEntry*) eNew);
828                         }
829
830                         eNew->v0->flags |= Vert_eEffected;
831                         eNew->v1->flags |= Vert_eEffected;
832                 }
833         } else {
834                 if (ss->syncState==eSyncState_Vert) {
835                         ss->syncState = eSyncState_Edge;
836                 } else if (ss->syncState!=eSyncState_Edge) {
837                         return eCCGError_InvalidSyncState;
838                 }
839
840                 e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
841                 if (!e || ((e->v0->vHDL!=e_vHDL0) || (e->v1->vHDL!=e_vHDL1))) {
842                         CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
843                         CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
844                         e = _edge_new(eHDL, v0, v1, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
845                         _ehash_insert(ss->eMap, (EHEntry*) e);
846                         e->v0->flags |= Vert_eEffected;
847                         e->v1->flags |= Vert_eEffected;
848                 } else {
849                         *prevp = e->next;
850                         _ehash_insert(ss->eMap, (EHEntry*) e);
851                         e->flags = 0;
852                         if ((e->v0->flags|e->v1->flags)&Vert_eChanged) {
853                                 e->v0->flags |= Vert_eEffected;
854                                 e->v1->flags |= Vert_eEffected;
855                         }
856                 }
857         }
858
859         return eCCGError_None;
860 }
861
862 CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs) {
863         void **prevp;
864         CCGFace *f, *fNew;
865         int j, k, topologyChanged = 0;
866
867         if (numVerts>ss->lenTempArrays) {
868                 int oldLen = ss->lenTempArrays;
869                 ss->lenTempArrays = (numVerts<ss->lenTempArrays*2)?ss->lenTempArrays*2:numVerts;
870                 ss->tempVerts = CCGSUBSURF_realloc(ss, ss->tempVerts, sizeof(*ss->tempVerts)*ss->lenTempArrays, sizeof(*ss->tempVerts)*oldLen);
871                 ss->tempEdges = CCGSUBSURF_realloc(ss, ss->tempEdges, sizeof(*ss->tempEdges)*ss->lenTempArrays, sizeof(*ss->tempEdges)*oldLen);
872         }
873
874         if (ss->syncState==eSyncState_Partial) {
875                 f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
876
877                 for (k=0; k<numVerts; k++) {
878                         ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
879                 }
880                 for (k=0; k<numVerts; k++) {
881                         ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
882                 }
883
884                 if (f) {
885                         if (    f->numVerts!=numVerts ||
886                                         memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
887                                         memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
888                                 topologyChanged = 1;
889                 }
890
891                 if (!f || topologyChanged) {
892                         fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
893
894                         if (f) {
895                                 ss->numGrids += numVerts - f->numVerts;
896
897                                 *prevp = fNew;
898                                 fNew->next = f->next;
899
900                                 _face_unlinkMarkAndFree(f, ss);
901                         } else {
902                                 ss->numGrids += numVerts;
903                                 _ehash_insert(ss->fMap, (EHEntry*) fNew);
904                         }
905
906                         for (k=0; k<numVerts; k++)
907                                 FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
908                 }
909         } else {
910                 if (ss->syncState==eSyncState_Vert || ss->syncState==eSyncState_Edge) {
911                         ss->syncState = eSyncState_Face;
912                 } else if (ss->syncState!=eSyncState_Face) {
913                         return eCCGError_InvalidSyncState;
914                 }
915
916                 f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
917
918                 for (k=0; k<numVerts; k++) {
919                         ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
920                 }
921                 for (k=0; k<numVerts; k++) {
922                         ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
923
924                         if (ss->allowEdgeCreation && !ss->tempEdges[k]) {
925                                 CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) -1, ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts], ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
926                                 _ehash_insert(ss->eMap, (EHEntry*) e);
927                                 e->v0->flags |= Vert_eEffected;
928                                 e->v1->flags |= Vert_eEffected;
929                         }
930                 }
931
932                 if (f) {
933                         if (    f->numVerts!=numVerts ||
934                                         memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
935                                         memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
936                                 topologyChanged = 1;
937                 }
938
939                 if (!f || topologyChanged) {
940                         f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
941                         _ehash_insert(ss->fMap, (EHEntry*) f);
942                         ss->numGrids += numVerts;
943
944                         for (k=0; k<numVerts; k++)
945                                 FACE_getVerts(f)[k]->flags |= Vert_eEffected;
946                 } else {
947                         *prevp = f->next;
948                         _ehash_insert(ss->fMap, (EHEntry*) f);
949                         f->flags = 0;
950                         ss->numGrids += f->numVerts;
951
952                         for (j=0; j<f->numVerts; j++) {
953                                 if (FACE_getVerts(f)[j]->flags&Vert_eChanged) {
954                                         for (k=0; k<f->numVerts; k++)
955                                                 FACE_getVerts(f)[k]->flags |= Vert_eEffected;
956                                         break;
957                                 }
958                         }
959                 }
960         }
961
962         return eCCGError_None;
963 }
964
965 static void ccgSubSurf__sync(CCGSubSurf *ss);
966 CCGError ccgSubSurf_processSync(CCGSubSurf *ss) {
967         if (ss->syncState==eSyncState_Partial) {
968                 ss->syncState = eSyncState_None;
969
970                 ccgSubSurf__sync(ss);
971         } else if (ss->syncState) {
972                 _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss);
973                 _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss);
974                 _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
975                 CCGSUBSURF_free(ss, ss->tempEdges);
976                 CCGSUBSURF_free(ss, ss->tempVerts);
977
978                 ss->lenTempArrays = 0;
979
980                 ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
981                 ss->tempVerts = NULL;
982                 ss->tempEdges = NULL;
983
984                 ss->syncState = eSyncState_None;
985
986                 ccgSubSurf__sync(ss);
987         } else {
988                 return eCCGError_InvalidSyncState;
989         }
990
991         return eCCGError_None;
992 }
993
994 static void ccgSubSurf__sync(CCGSubSurf *ss) {
995         CCGVert **effectedV;
996         CCGEdge **effectedE;
997         CCGFace **effectedF;
998         int numEffectedV, numEffectedE, numEffectedF;
999         int subdivLevels = ss->subdivLevels;
1000         int vertDataSize = ss->meshIFC.vertDataSize;
1001         int i,ptrIdx,cornerIdx;
1002         int S,x,y;
1003         void *q = ss->q, *r = ss->r;
1004         int curLvl, nextLvl;
1005         int j;
1006
1007         effectedV = CCGSUBSURF_alloc(ss, sizeof(*effectedV)*ss->vMap->numEntries);
1008         effectedE = CCGSUBSURF_alloc(ss, sizeof(*effectedE)*ss->eMap->numEntries);
1009         effectedF = CCGSUBSURF_alloc(ss, sizeof(*effectedF)*ss->fMap->numEntries);
1010         numEffectedV = numEffectedE = numEffectedF = 0;
1011         for (i=0; i<ss->vMap->curSize; i++) {
1012                 CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
1013                 for (; v; v = v->next) {
1014                         if (v->flags&Vert_eEffected) {
1015                                 effectedV[numEffectedV++] = v;
1016
1017                                 for (j=0; j<v->numEdges; j++) {
1018                                         CCGEdge *e = v->edges[j];
1019                                         if (!(e->flags&Edge_eEffected)) {
1020                                                 effectedE[numEffectedE++] = e;
1021                                                 e->flags |= Edge_eEffected;
1022                                         }
1023                                 }
1024
1025                                 for (j=0; j<v->numFaces; j++) {
1026                                         CCGFace *f = v->faces[j];
1027                                         if (!(f->flags&Face_eEffected)) {
1028                                                 effectedF[numEffectedF++] = f;
1029                                                 f->flags |= Face_eEffected;
1030                                         }
1031                                 }
1032                         }
1033                 }
1034         }
1035
1036 #define VERT_getCo(v, lvl)                              _vert_getCo(v, lvl, vertDataSize)
1037 #define EDGE_getCo(e, lvl, x)                   _edge_getCo(e, lvl, x, vertDataSize)
1038 #define FACE_getIECo(f, lvl, S, x)              _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
1039 #define FACE_getIFCo(f, lvl, S, x, y)   _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
1040         curLvl = 0;
1041         nextLvl = curLvl+1;
1042
1043         for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
1044                 CCGFace *f = effectedF[ptrIdx];
1045                 void *co = FACE_getCenterData(f);
1046                 ss->meshIFC.vertDataZero(ss->meshData, co);
1047                 for (i=0; i<f->numVerts; i++) {
1048                         ss->meshIFC.vertDataAdd(ss->meshData, co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
1049                 }
1050                 ss->meshIFC.vertDataMulN(ss->meshData, co, 1.0f/f->numVerts);
1051
1052                 f->flags = 0;
1053         }
1054         for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
1055                 CCGEdge *e = effectedE[ptrIdx];
1056                 void *co = EDGE_getCo(e, nextLvl, 1);
1057 #ifdef USE_CREASING
1058                 float sharpness = EDGE_getSharpness(e, curLvl, ss);
1059
1060                 if (_edge_isBoundary(e) || sharpness>=1.0) {
1061                         ss->meshIFC.vertDataCopy(ss->meshData, co, VERT_getCo(e->v0, curLvl));
1062                         ss->meshIFC.vertDataAdd(ss->meshData, co, VERT_getCo(e->v1, curLvl));
1063                         ss->meshIFC.vertDataMulN(ss->meshData, co, 0.5f);
1064                 } else {
1065                         int numFaces = 0;
1066                         ss->meshIFC.vertDataCopy(ss->meshData, q, VERT_getCo(e->v0, curLvl));
1067                         ss->meshIFC.vertDataAdd(ss->meshData, q, VERT_getCo(e->v1, curLvl));
1068                         for (i=0; i<e->numFaces; i++) {
1069                                 CCGFace *f = e->faces[i];
1070                                 ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getCenterData(f));
1071                                 numFaces++;
1072                         }
1073                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/(2.0f+numFaces));
1074
1075                         ss->meshIFC.vertDataCopy(ss->meshData, r, VERT_getCo(e->v0, curLvl));
1076                         ss->meshIFC.vertDataAdd(ss->meshData, r, VERT_getCo(e->v1, curLvl));
1077                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.5f);
1078
1079                         ss->meshIFC.vertDataCopy(ss->meshData, co, q);
1080                         ss->meshIFC.vertDataSub(ss->meshData, r, q);
1081                         ss->meshIFC.vertDataMulN(ss->meshData, r, sharpness);
1082                         ss->meshIFC.vertDataAdd(ss->meshData, co, r);
1083                 }
1084 #else
1085                 if (_edge_isBoundary(e)) {
1086                         ss->meshIFC.vertDataCopy(ss->meshData, co, VERT_getCo(e->v0, curLvl));
1087                         ss->meshIFC.vertDataAdd(ss->meshData, co, VERT_getCo(e->v1, curLvl));
1088                         ss->meshIFC.vertDataMulN(ss->meshData, co, 0.5f);
1089                 } else {
1090                         int numFaces = 0;
1091                         ss->meshIFC.vertDataCopy(ss->meshData, co, VERT_getCo(e->v0, curLvl));
1092                         ss->meshIFC.vertDataAdd(ss->meshData, co, VERT_getCo(e->v1, curLvl));
1093                         for (i=0; i<e->numFaces; i++) {
1094                                 CCGFace *f = e->faces[i];
1095                                 ss->meshIFC.vertDataAdd(ss->meshData, co, FACE_getCenterData(f));
1096                                 numFaces++;
1097                         }
1098                         ss->meshIFC.vertDataMulN(ss->meshData, co, 1.0f/(2.0f+numFaces));
1099                 }
1100 #endif
1101
1102                 e->flags = 0;
1103         }
1104         for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
1105                 CCGVert *v = effectedV[ptrIdx];
1106                 void *co = VERT_getCo(v, curLvl);
1107                 void *nCo = VERT_getCo(v, nextLvl);
1108
1109 #ifdef USE_CREASING
1110                 int sharpCount = 0;
1111                 float avgSharpness = 0.0;
1112                 CCGVert *sharpV0 = NULL, *sharpV1 = NULL;
1113
1114                 for (i=0; i<v->numEdges; i++) {
1115                         CCGEdge *e = v->edges[i];
1116                         float sharpness = EDGE_getSharpness(e, curLvl, ss);
1117
1118                         if (sharpness!=0.0f) {
1119                                 sharpCount++;
1120                                 avgSharpness += sharpness;
1121
1122                                 if (!sharpV0) {
1123                                         sharpV0 = _edge_getOtherVert(e, v);
1124                                 } else if (!sharpV1) {
1125                                         sharpV1 = _edge_getOtherVert(e, v);
1126                                 }
1127                         }
1128                 }
1129
1130                 avgSharpness /= sharpCount;
1131                 if (avgSharpness>1.0) {
1132                         avgSharpness = 1.0;
1133                 }
1134
1135                 if (!v->numEdges || sharpCount>2) {
1136                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1137                 } else if (_vert_isBoundary(v) && sharpCount<2) {
1138                         int numBoundary = 0;
1139
1140                         ss->meshIFC.vertDataZero(ss->meshData, r);
1141                         for (i=0; i<v->numEdges; i++) {
1142                                 CCGEdge *e = v->edges[i];
1143                                 if (_edge_isBoundary(e)) {
1144                                         ss->meshIFC.vertDataAdd(ss->meshData, r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
1145                                         numBoundary++;
1146                                 }
1147                         }
1148                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1149                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1150                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25f/numBoundary);
1151                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1152                 } else {
1153                         int numEdges = 0, numFaces = 0;
1154
1155                         ss->meshIFC.vertDataZero(ss->meshData, q);
1156                         for (i=0; i<v->numFaces; i++) {
1157                                 CCGFace *f = v->faces[i];
1158                                 ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getCenterData(f));
1159                                 numFaces++;
1160                         }
1161                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/numFaces);
1162                         ss->meshIFC.vertDataZero(ss->meshData, r);
1163                         for (i=0; i<v->numEdges; i++) {
1164                                 CCGEdge *e = v->edges[i];
1165                                 ss->meshIFC.vertDataAdd(ss->meshData, r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
1166                                 numEdges++;
1167                         }
1168                         ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0f/numEdges);
1169
1170                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1171                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, numEdges-2.0f);
1172                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1173                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1174                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/numEdges);
1175
1176                         if (sharpCount==2) {
1177                                 ss->meshIFC.vertDataCopy(ss->meshData, q, co);
1178                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 6.0f);
1179                                 ss->meshIFC.vertDataAdd(ss->meshData, q, VERT_getCo(sharpV0, curLvl));
1180                                 ss->meshIFC.vertDataAdd(ss->meshData, q, VERT_getCo(sharpV1, curLvl));
1181                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 1/8.0f);
1182
1183                                 ss->meshIFC.vertDataSub(ss->meshData, q, nCo);
1184                                 ss->meshIFC.vertDataMulN(ss->meshData, q, avgSharpness);
1185                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1186                         }
1187                 }
1188 #else
1189                 if (!v->numEdges) {
1190                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1191                 } else if (_vert_isBoundary(v)) {
1192                         int numBoundary = 0;
1193
1194                         ss->meshIFC.vertDataZero(ss->meshData, r);
1195                         for (i=0; i<v->numEdges; i++) {
1196                                 CCGEdge *e = v->edges[i];
1197                                 if (_edge_isBoundary(e)) {
1198                                         ss->meshIFC.vertDataAdd(ss->meshData, r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
1199                                         numBoundary++;
1200                                 }
1201                         }
1202                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1203                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1204                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25f/numBoundary);
1205                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1206                 } else {
1207                         int numEdges = 0, numFaces = 0;
1208
1209                         ss->meshIFC.vertDataZero(ss->meshData, q);
1210                         for (i=0; i<v->numFaces; i++) {
1211                                 CCGFace *f = v->faces[i];
1212                                 ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getCenterData(f));
1213                                 numFaces++;
1214                         }
1215                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/numFaces);
1216                         ss->meshIFC.vertDataZero(ss->meshData, r);
1217                         for (i=0; i<v->numEdges; i++) {
1218                                 CCGEdge *e = v->edges[i];
1219                                 ss->meshIFC.vertDataAdd(ss->meshData, r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
1220                                 numEdges++;
1221                         }
1222                         ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0f/numEdges);
1223
1224                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1225                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, numEdges-2.0f);
1226                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1227                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1228                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/numEdges);
1229                 }
1230 #endif
1231
1232                 v->flags = 0;
1233         }
1234
1235         if (ss->useAgeCounts) {
1236                 for (i=0; i<numEffectedV; i++) {
1237                         CCGVert *v = effectedV[i];
1238                         byte *userData = ccgSubSurf_getVertUserData(ss, v);
1239                         *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
1240                 }
1241
1242                 for (i=0; i<numEffectedE; i++) {
1243                         CCGEdge *e = effectedE[i];
1244                         byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
1245                         *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
1246                 }
1247
1248                 for (i=0; i<numEffectedF; i++) {
1249                         CCGFace *f = effectedF[i];
1250                         byte *userData = ccgSubSurf_getFaceUserData(ss, f);
1251                         *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
1252                 }
1253         }
1254
1255         for (i=0; i<numEffectedE; i++) {
1256                 CCGEdge *e = effectedE[i];
1257                 ss->meshIFC.vertDataCopy(ss->meshData, EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
1258                 ss->meshIFC.vertDataCopy(ss->meshData, EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
1259         }
1260         for (i=0; i<numEffectedF; i++) {
1261                 CCGFace *f = effectedF[i];
1262                 for (S=0; S<f->numVerts; S++) {
1263                         CCGEdge *e = FACE_getEdges(f)[S];
1264                         CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
1265
1266                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
1267                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
1268                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
1269                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
1270
1271                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
1272                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
1273                 }
1274         }
1275
1276         for (curLvl=1; curLvl<subdivLevels; curLvl++) {
1277                 int edgeSize = 1 + (1<<curLvl);
1278                 int gridSize = 1 + (1<<(curLvl-1));
1279                 nextLvl = curLvl+1;
1280
1281                 for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
1282                         CCGFace *f = (CCGFace*) effectedF[ptrIdx];
1283
1284                                 /* interior face midpoints
1285                                  *  o old interior face points
1286                                  */
1287                         for (S=0; S<f->numVerts; S++) {
1288                                 for (y=0; y<gridSize-1; y++) {
1289                                         for (x=0; x<gridSize-1; x++) {
1290                                                 int fx = 1 + 2*x;
1291                                                 int fy = 1 + 2*y;
1292                                                 void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
1293                                                 void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
1294                                                 void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
1295                                                 void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
1296                                                 void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
1297
1298                                                 ss->meshIFC.vertDataAvg4(ss->meshData, co, co0, co1, co2, co3);
1299                                         }
1300                                 }
1301                         }
1302
1303                                 /* interior edge midpoints
1304                                  *  o old interior edge points
1305                                  *  o new interior face midpoints
1306                                  */
1307                         for (S=0; S<f->numVerts; S++) {
1308                                 for (x=0; x<gridSize-1; x++) {
1309                                         int fx = x*2 + 1;
1310                                         void *co0 = FACE_getIECo(f, curLvl, S, x+0);
1311                                         void *co1 = FACE_getIECo(f, curLvl, S, x+1);
1312                                         void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
1313                                         void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
1314                                         void *co = FACE_getIECo(f, nextLvl, S, fx);
1315                                         
1316                                         ss->meshIFC.vertDataAvg4(ss->meshData, co, co0, co1, co2, co3);
1317                                 }
1318
1319                                                 /* interior face interior edge midpoints
1320                                                  *  o old interior face points
1321                                                  *  o new interior face midpoints
1322                                                  */
1323
1324                                         /* vertical */
1325                                 for (x=1; x<gridSize-1; x++) {
1326                                         for (y=0; y<gridSize-1; y++) {
1327                                                 int fx = x*2;
1328                                                 int fy = y*2+1;
1329                                                 void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
1330                                                 void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
1331                                                 void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
1332                                                 void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
1333                                                 void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
1334
1335                                                 ss->meshIFC.vertDataAvg4(ss->meshData, co, co0, co1, co2, co3);
1336                                         }
1337                                 }
1338
1339                                         /* horizontal */
1340                                 for (y=1; y<gridSize-1; y++) {
1341                                         for (x=0; x<gridSize-1; x++) {
1342                                                 int fx = x*2+1;
1343                                                 int fy = y*2;
1344                                                 void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
1345                                                 void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
1346                                                 void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
1347                                                 void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
1348                                                 void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
1349
1350                                                 ss->meshIFC.vertDataAvg4(ss->meshData, co, co0, co1, co2, co3);
1351                                         }
1352                                 }
1353                         }
1354                 }
1355
1356                         /* exterior edge midpoints
1357                          *  o old exterior edge points
1358                          *  o new interior face midpoints
1359                          */
1360                 for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
1361                         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
1362
1363 #ifdef USE_CREASING
1364                         float sharpness = EDGE_getSharpness(e, curLvl, ss);
1365
1366                         if (_edge_isBoundary(e) || sharpness>1.0) {
1367                                 for (x=0; x<edgeSize-1; x++) {
1368                                         int fx = x*2 + 1;
1369                                         void *co0 = EDGE_getCo(e, curLvl, x+0);
1370                                         void *co1 = EDGE_getCo(e, curLvl, x+1);
1371                                         void *co = EDGE_getCo(e, nextLvl, fx);
1372
1373                                         ss->meshIFC.vertDataCopy(ss->meshData, co, co0);
1374                                         ss->meshIFC.vertDataAdd(ss->meshData, co, co1);
1375                                         ss->meshIFC.vertDataMulN(ss->meshData, co, 0.5);
1376                                 }
1377                         } else {
1378                                 for (x=0; x<edgeSize-1; x++) {
1379                                         int fx = x*2 + 1;
1380                                         void *co0 = EDGE_getCo(e, curLvl, x+0);
1381                                         void *co1 = EDGE_getCo(e, curLvl, x+1);
1382                                         void *co = EDGE_getCo(e, nextLvl, fx);
1383                                         int numFaces = 0;
1384
1385                                         ss->meshIFC.vertDataCopy(ss->meshData, q, co0);
1386                                         ss->meshIFC.vertDataAdd(ss->meshData, q, co1);
1387
1388                                         for (i=0; i<e->numFaces; i++) {
1389                                                 CCGFace *f = e->faces[i];
1390                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
1391                                                 numFaces++;
1392                                         }
1393
1394                                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/(2.0f+numFaces));
1395
1396                                         ss->meshIFC.vertDataCopy(ss->meshData, r, co0);
1397                                         ss->meshIFC.vertDataAdd(ss->meshData, r, co1);
1398                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.5);
1399
1400                                         ss->meshIFC.vertDataCopy(ss->meshData, co, q);
1401                                         ss->meshIFC.vertDataSub(ss->meshData, r, q);
1402                                         ss->meshIFC.vertDataMulN(ss->meshData, r, sharpness);
1403                                         ss->meshIFC.vertDataAdd(ss->meshData, co, r);
1404                                 }
1405                         }
1406 #else
1407                         if (_edge_isBoundary(e)) {
1408                                 for (x=0; x<edgeSize-1; x++) {
1409                                         int fx = x*2 + 1;
1410                                         void *co0 = EDGE_getCo(e, curLvl, x+0);
1411                                         void *co1 = EDGE_getCo(e, curLvl, x+1);
1412                                         void *co = EDGE_getCo(e, nextLvl, fx);
1413
1414                                         ss->meshIFC.vertDataCopy(ss->meshData, co, co0);
1415                                         ss->meshIFC.vertDataAdd(ss->meshData, co, co1);
1416                                         ss->meshIFC.vertDataMulN(ss->meshData, co, 0.5);
1417                                 }
1418                         } else {
1419                                 for (x=0; x<edgeSize-1; x++) {
1420                                         int fx = x*2 + 1;
1421                                         void *co0 = EDGE_getCo(e, curLvl, x+0);
1422                                         void *co1 = EDGE_getCo(e, curLvl, x+1);
1423                                         void *co = EDGE_getCo(e, nextLvl, fx);
1424                                         int numFaces = 0;
1425
1426                                         ss->meshIFC.vertDataCopy(ss->meshData, co, co0);
1427                                         ss->meshIFC.vertDataAdd(ss->meshData, co, co1);
1428
1429                                         for (i=0; i<e->numFaces; i++) {
1430                                                 CCGFace *f = e->faces[i];
1431                                                 ss->meshIFC.vertDataAdd(ss->meshData, co, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
1432                                                 numFaces++;
1433                                         }
1434
1435                                         ss->meshIFC.vertDataMulN(ss->meshData, co, 1.0f/(2.0f+numFaces));
1436                                 }
1437                         }
1438 #endif
1439                 }
1440
1441                         /* exterior vertex shift
1442                          *  o old vertex points (shifting)
1443                          *  o old exterior edge points
1444                          *  o new interior face midpoints
1445                          */
1446                 for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
1447                         CCGVert *v = (CCGVert*) effectedV[ptrIdx];
1448                         void *co = VERT_getCo(v, curLvl);
1449                         void *nCo = VERT_getCo(v, nextLvl);
1450
1451 #ifdef USE_CREASING
1452                         int sharpCount = 0;
1453                         float avgSharpness = 0.0;
1454                         CCGEdge *sharpE0 = NULL, *sharpE1 = NULL;
1455
1456                         for (i=0; i<v->numEdges; i++) {
1457                                 CCGEdge *e = v->edges[i];
1458                                 float sharpness = EDGE_getSharpness(e, curLvl, ss);
1459
1460                                 if (sharpness!=0.0f) {
1461                                         sharpCount++;
1462                                         avgSharpness += sharpness;
1463
1464                                         if (!sharpE0) {
1465                                                 sharpE0 = e;
1466                                         } else if (!sharpE1) {
1467                                                 sharpE1 = e;
1468                                         }
1469                                 }
1470                         }
1471
1472                         avgSharpness /= sharpCount;
1473                         if (avgSharpness>1.0) {
1474                                 avgSharpness = 1.0;
1475                         }
1476
1477                         if (!v->numEdges || sharpCount>2) {
1478                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1479                         } else if (_vert_isBoundary(v) && sharpCount<2) {
1480                                 int numBoundary = 0;
1481
1482                                 ss->meshIFC.vertDataZero(ss->meshData, r);
1483                                 for (i=0; i<v->numEdges; i++) {
1484                                         CCGEdge *e = v->edges[i];
1485                                         if (_edge_isBoundary(e)) {
1486                                                 ss->meshIFC.vertDataAdd(ss->meshData, r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
1487                                                 numBoundary++;
1488                                         }
1489                                 }
1490
1491                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1492                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1493                                 ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25f/numBoundary);
1494                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1495                         } else {
1496                                 int cornerIdx = (1 + (1<<(curLvl))) - 2;
1497                                 int numEdges = 0, numFaces = 0;
1498
1499                                 ss->meshIFC.vertDataZero(ss->meshData, q);
1500                                 for (i=0; i<v->numFaces; i++) {
1501                                         CCGFace *f = v->faces[i];
1502                                         ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
1503                                         numFaces++;
1504                                 }
1505                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/numFaces);
1506                                 ss->meshIFC.vertDataZero(ss->meshData, r);
1507                                 for (i=0; i<v->numEdges; i++) {
1508                                         CCGEdge *e = v->edges[i];
1509                                         ss->meshIFC.vertDataAdd(ss->meshData, r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
1510                                         numEdges++;
1511                                 }
1512                                 ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0f/numEdges);
1513
1514                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1515                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, numEdges-2.0f);
1516                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1517                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1518                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/numEdges);
1519
1520                                 if (sharpCount==2) {
1521                                         ss->meshIFC.vertDataCopy(ss->meshData, q, co);
1522                                         ss->meshIFC.vertDataMulN(ss->meshData, q, 6.0f);
1523                                         ss->meshIFC.vertDataAdd(ss->meshData, q, _edge_getCoVert(sharpE0, v, curLvl, 1, vertDataSize));
1524                                         ss->meshIFC.vertDataAdd(ss->meshData, q, _edge_getCoVert(sharpE1, v, curLvl, 1, vertDataSize));
1525                                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1/8.0f);
1526
1527                                         ss->meshIFC.vertDataSub(ss->meshData, q, nCo);
1528                                         ss->meshIFC.vertDataMulN(ss->meshData, q, avgSharpness);
1529                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1530                                 }
1531                         }
1532 #else
1533                         if (!v->numEdges) {
1534                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1535                         } else if (_vert_isBoundary(v)) {
1536                                 int numBoundary = 0;
1537
1538                                 ss->meshIFC.vertDataZero(ss->meshData, r);
1539                                 for (i=0; i<v->numEdges; i++) {
1540                                         CCGEdge *e = v->edges[i];
1541                                         if (_edge_isBoundary(e)) {
1542                                                 ss->meshIFC.vertDataAdd(ss->meshData, r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
1543                                                 numBoundary++;
1544                                         }
1545                                 }
1546
1547                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1548                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1549                                 ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25f/numBoundary);
1550                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1551                         } else {
1552                                 int cornerIdx = (1 + (1<<(curLvl))) - 2;
1553                                 int numEdges = 0, numFaces = 0;
1554
1555                                 ss->meshIFC.vertDataZero(ss->meshData, q);
1556                                 for (i=0; i<v->numFaces; i++) {
1557                                         CCGFace *f = v->faces[i];
1558                                         ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
1559                                         numFaces++;
1560                                 }
1561                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/numFaces);
1562                                 ss->meshIFC.vertDataZero(ss->meshData, r);
1563                                 for (i=0; i<v->numEdges; i++) {
1564                                         CCGEdge *e = v->edges[i];
1565                                         ss->meshIFC.vertDataAdd(ss->meshData, r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
1566                                         numEdges++;
1567                                 }
1568                                 ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0f/numEdges);
1569
1570                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1571                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, numEdges-2.0f);
1572                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1573                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1574                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/numEdges);
1575                         }
1576 #endif
1577                 }
1578
1579                         /* exterior edge interior shift
1580                          *  o old exterior edge midpoints (shifting)
1581                          *  o old exterior edge midpoints
1582                          *  o new interior face midpoints
1583                          */
1584                 for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
1585                         CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
1586
1587 #ifdef USE_CREASING
1588                         float sharpness = EDGE_getSharpness(e, curLvl, ss);
1589                         int sharpCount = 0;
1590                         float avgSharpness = 0.0;
1591
1592                         if (sharpness!=0.0f) {
1593                                 sharpCount = 2;
1594                                 avgSharpness += 2*sharpness;
1595                         } else {
1596                                 sharpCount = 0;
1597                                 avgSharpness = 0;
1598                         }
1599
1600                         avgSharpness /= sharpCount;
1601                         if (avgSharpness>1.0) {
1602                                 avgSharpness = 1.0;
1603                         }
1604
1605                         if (_edge_isBoundary(e) && sharpCount<2) {
1606                                 for (x=1; x<edgeSize-1; x++) {
1607                                         int fx = x*2;
1608                                         void *co = EDGE_getCo(e, curLvl, x);
1609                                         void *nCo = EDGE_getCo(e, nextLvl, fx);
1610                                         ss->meshIFC.vertDataCopy(ss->meshData, r, EDGE_getCo(e, curLvl, x-1));
1611                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x+1));
1612                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.5);
1613                                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1614                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1615                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25);
1616                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1617                                 }
1618                         } else {
1619                                 for (x=1; x<edgeSize-1; x++) {
1620                                         int fx = x*2;
1621                                         void *co = EDGE_getCo(e, curLvl, x);
1622                                         void *nCo = EDGE_getCo(e, nextLvl, fx);
1623                                         int numFaces = 0;
1624
1625                                         ss->meshIFC.vertDataZero(ss->meshData, q);
1626                                         ss->meshIFC.vertDataZero(ss->meshData, r);
1627                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x-1));
1628                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x+1));
1629                                         for (i=0; i<e->numFaces; i++) {
1630                                                 CCGFace *f = e->faces[i];
1631                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
1632                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
1633
1634                                                 ss->meshIFC.vertDataAdd(ss->meshData, r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
1635                                                 numFaces++;
1636                                         }
1637                                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0/(numFaces*2.0f));
1638                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0/(2.0f + numFaces));
1639
1640                                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1641                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, (float) numFaces);
1642                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1643                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1644                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/(2+numFaces));
1645
1646                                         if (sharpCount==2) {
1647                                                 ss->meshIFC.vertDataCopy(ss->meshData, q, co);
1648                                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 6.0f);
1649                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, EDGE_getCo(e, curLvl, x-1));
1650                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, EDGE_getCo(e, curLvl, x+1));
1651                                                 ss->meshIFC.vertDataMulN(ss->meshData, q, 1/8.0f);
1652
1653                                                 ss->meshIFC.vertDataSub(ss->meshData, q, nCo);
1654                                                 ss->meshIFC.vertDataMulN(ss->meshData, q, avgSharpness);
1655                                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1656                                         }
1657                                 }
1658                         }
1659 #else
1660                         if (_edge_isBoundary(e)) {
1661                                 for (x=1; x<edgeSize-1; x++) {
1662                                         int fx = x*2;
1663                                         void *co = EDGE_getCo(e, curLvl, x);
1664                                         void *nCo = EDGE_getCo(e, nextLvl, fx);
1665                                         ss->meshIFC.vertDataCopy(ss->meshData, r, EDGE_getCo(e, curLvl, x-1));
1666                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x+1));
1667                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.5);
1668                                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1669                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.75);
1670                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 0.25);
1671                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1672                                 }
1673                         } else {
1674                                 for (x=1; x<edgeSize-1; x++) {
1675                                         int fx = x*2;
1676                                         void *co = EDGE_getCo(e, curLvl, x);
1677                                         void *nCo = EDGE_getCo(e, nextLvl, fx);
1678                                         int numFaces = 0;
1679
1680                                         ss->meshIFC.vertDataZero(ss->meshData, q);
1681                                         ss->meshIFC.vertDataZero(ss->meshData, r);
1682                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x-1));
1683                                         ss->meshIFC.vertDataAdd(ss->meshData, r, EDGE_getCo(e, curLvl, x+1));
1684                                         for (i=0; i<e->numFaces; i++) {
1685                                                 CCGFace *f = e->faces[i];
1686                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
1687                                                 ss->meshIFC.vertDataAdd(ss->meshData, q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
1688
1689                                                 ss->meshIFC.vertDataAdd(ss->meshData, r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
1690                                                 numFaces++;
1691                                         }
1692                                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0/(numFaces*2.0f));
1693                                         ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0/(2.0f + numFaces));
1694
1695                                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1696                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, (float) numFaces);
1697                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, q);
1698                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1699                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 1.0f/(2+numFaces));
1700                                 }
1701                         }
1702 #endif
1703                 }
1704
1705                 for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
1706                         CCGFace *f = (CCGFace*) effectedF[ptrIdx];
1707
1708                                 /* interior center point shift
1709                                  *  o old face center point (shifting)
1710                                  *  o old interior edge points
1711                                  *  o new interior face midpoints
1712                                  */
1713                         ss->meshIFC.vertDataZero(ss->meshData, q);
1714                         for (S=0; S<f->numVerts; S++) {
1715                                 ss->meshIFC.vertDataAdd(ss->meshData, q, FACE_getIFCo(f, nextLvl, S, 1, 1));
1716                         }
1717                         ss->meshIFC.vertDataMulN(ss->meshData, q, 1.0f/f->numVerts);
1718                         ss->meshIFC.vertDataZero(ss->meshData, r);
1719                         for (S=0; S<f->numVerts; S++) {
1720                                 ss->meshIFC.vertDataAdd(ss->meshData, r, FACE_getIECo(f, curLvl, S, 1));
1721                         }
1722                         ss->meshIFC.vertDataMulN(ss->meshData, r, 1.0f/f->numVerts);
1723
1724                         ss->meshIFC.vertDataMulN(ss->meshData, FACE_getCenterData(f), f->numVerts-2.0f);
1725                         ss->meshIFC.vertDataAdd(ss->meshData, FACE_getCenterData(f), q);
1726                         ss->meshIFC.vertDataAdd(ss->meshData, FACE_getCenterData(f), r);
1727                         ss->meshIFC.vertDataMulN(ss->meshData, FACE_getCenterData(f), 1.0f/f->numVerts);
1728
1729                         for (S=0; S<f->numVerts; S++) {
1730                                         /* interior face shift
1731                                          *  o old interior face point (shifting)
1732                                          *  o new interior edge midpoints
1733                                          *  o new interior face midpoints
1734                                          */
1735                                 for (x=1; x<gridSize-1; x++) {
1736                                         for (y=1; y<gridSize-1; y++) {
1737                                                 int fx = x*2;
1738                                                 int fy = y*2;
1739                                                 void *co = FACE_getIFCo(f, curLvl, S, x, y);
1740                                                 void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
1741                                                 
1742                                                 ss->meshIFC.vertDataAvg4(ss->meshData, q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
1743                                                         FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
1744                                                         FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
1745                                                         FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
1746
1747                                                 ss->meshIFC.vertDataAvg4(ss->meshData, r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
1748                                                         FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
1749                                                         FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
1750                                                         FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
1751
1752                                                 ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1753                                                 ss->meshIFC.vertDataSub(ss->meshData, nCo, q);
1754                                                 ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.25f);
1755                                                 ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1756                                         }
1757                                 }
1758
1759                                         /* interior edge interior shift
1760                                          *  o old interior edge point (shifting)
1761                                          *  o new interior edge midpoints
1762                                          *  o new interior face midpoints
1763                                          */
1764                                 for (x=1; x<gridSize-1; x++) {
1765                                         int fx = x*2;
1766                                         void *co = FACE_getIECo(f, curLvl, S, x);
1767                                         void *nCo = FACE_getIECo(f, nextLvl, S, fx);
1768                                         
1769                                         ss->meshIFC.vertDataAvg4(ss->meshData, q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
1770                                                 FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
1771                                                 FACE_getIFCo(f, nextLvl, S, fx+1, +1),
1772                                                 FACE_getIFCo(f, nextLvl, S, fx-1, +1));
1773
1774                                         ss->meshIFC.vertDataAvg4(ss->meshData, r, FACE_getIECo(f, nextLvl, S, fx-1),
1775                                                 FACE_getIECo(f, nextLvl, S, fx+1),
1776                                                 FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
1777                                                 FACE_getIFCo(f, nextLvl, S, fx, 1));
1778
1779                                         ss->meshIFC.vertDataCopy(ss->meshData, nCo, co);
1780                                         ss->meshIFC.vertDataSub(ss->meshData, nCo, q);
1781                                         ss->meshIFC.vertDataMulN(ss->meshData, nCo, 0.25f);
1782                                         ss->meshIFC.vertDataAdd(ss->meshData, nCo, r);
1783                                 }
1784                         }
1785                 }
1786
1787
1788
1789                         /* copy down */
1790                 edgeSize = 1 + (1<<(nextLvl));
1791                 gridSize = 1 + (1<<((nextLvl)-1));
1792                 cornerIdx = gridSize-1;
1793                 for (i=0; i<numEffectedE; i++) {
1794                         CCGEdge *e = effectedE[i];
1795                         ss->meshIFC.vertDataCopy(ss->meshData, EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
1796                         ss->meshIFC.vertDataCopy(ss->meshData, EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
1797                 }
1798                 for (i=0; i<numEffectedF; i++) {
1799                         CCGFace *f = effectedF[i];
1800                         for (S=0; S<f->numVerts; S++) {
1801                                 CCGEdge *e = FACE_getEdges(f)[S];
1802                                 CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
1803
1804                                 ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
1805                                 ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
1806                                 ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
1807                                 ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
1808                                 for (x=1; x<gridSize-1; x++) {
1809                                         void *co = FACE_getIECo(f, nextLvl, S, x);
1810                                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, x, 0), co);
1811                                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
1812                                 }
1813                                 for (x=0; x<gridSize-1; x++) {
1814                                         int eI = gridSize-1-x;
1815                                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
1816                                         ss->meshIFC.vertDataCopy(ss->meshData, FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
1817                                 }
1818                         }
1819                 }
1820         }
1821 #undef VERT_getCo
1822 #undef EDGE_getCo
1823 #undef FACE_getIECo
1824 #undef FACE_getIFCo
1825
1826         CCGSUBSURF_free(ss, effectedF);
1827         CCGSUBSURF_free(ss, effectedE);
1828         CCGSUBSURF_free(ss, effectedV);
1829 }
1830
1831 /*** External API accessor functions ***/
1832
1833 int ccgSubSurf_getNumVerts(CCGSubSurf *ss) {
1834         return ss->vMap->numEntries;
1835 }
1836 int ccgSubSurf_getNumEdges(CCGSubSurf *ss) {
1837         return ss->eMap->numEntries;
1838 }
1839 int ccgSubSurf_getNumFaces(CCGSubSurf *ss) {
1840         return ss->fMap->numEntries;
1841 }
1842
1843 CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) {
1844         return (CCGVert*) _ehash_lookup(ss->vMap, v);
1845 }
1846 CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) {
1847         return (CCGEdge*) _ehash_lookup(ss->eMap, e);
1848 }
1849 CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) {
1850         return (CCGFace*) _ehash_lookup(ss->fMap, f);
1851 }
1852
1853 int ccgSubSurf_getSubdivisionLevels(CCGSubSurf *ss) {
1854         return ss->subdivLevels;
1855 }
1856 int ccgSubSurf_getEdgeSize(CCGSubSurf *ss) {
1857         return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
1858 }
1859 int ccgSubSurf_getEdgeLevelSize(CCGSubSurf *ss, int level) {
1860         if (level<1 || level>ss->subdivLevels) {
1861                 return -1;
1862         } else {
1863                 return 1 + (1<<level);
1864         }
1865 }
1866 int ccgSubSurf_getGridSize(CCGSubSurf *ss) {
1867         return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
1868 }
1869 int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) {
1870         if (level<1 || level>ss->subdivLevels) {
1871                 return -1;
1872         } else {
1873                 return 1 + (1<<(level-1));
1874         }
1875 }
1876
1877 /* Vert accessors */
1878
1879 CCGVertHDL ccgSubSurf_getVertVertHandle(CCGSubSurf *ss, CCGVert *v) {
1880         return v->vHDL;
1881 }
1882 int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) {
1883         if (ss->useAgeCounts) {
1884                 byte *userData = ccgSubSurf_getVertUserData(ss, v);
1885                 return ss->currentAge - *((int*) &userData[ss->vertUserAgeOffset]);
1886         } else {
1887                 return 0;
1888         }
1889 }
1890 void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) {
1891         return VERT_getLevelData(v) + ss->meshIFC.vertDataSize*(ss->subdivLevels+1);
1892 }
1893 int ccgSubSurf_getVertNumFaces(CCGSubSurf *ss, CCGVert *v) {
1894         return v->numFaces;
1895 }
1896 CCGFace *ccgSubSurf_getVertFace(CCGSubSurf *ss, CCGVert *v, int index) {
1897         if (index<0 || index>=v->numFaces) {
1898                 return NULL;
1899         } else {
1900                 return v->faces[index];
1901         }
1902 }
1903 int ccgSubSurf_getVertNumEdges(CCGSubSurf *ss, CCGVert *v) {
1904         return v->numEdges;
1905 }
1906 CCGEdge *ccgSubSurf_getVertEdge(CCGSubSurf *ss, CCGVert *v, int index) {
1907         if (index<0 || index>=v->numEdges) {
1908                 return NULL;
1909         } else {
1910                 return v->edges[index];
1911         }
1912 }
1913 void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) {
1914         return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
1915 }
1916 void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) {
1917         if (level<0 || level>ss->subdivLevels) {
1918                 return NULL;
1919         } else {
1920                 return _vert_getCo(v, level, ss->meshIFC.vertDataSize);
1921         }
1922 }
1923
1924 /* Edge accessors */
1925
1926 CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGSubSurf *ss, CCGEdge *e) {
1927         return e->eHDL;
1928 }
1929 int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) {
1930         if (ss->useAgeCounts) {
1931                 byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
1932                 return ss->currentAge - *((int*) &userData[ss->edgeUserAgeOffset]);
1933         } else {
1934                 return 0;
1935         }
1936 }
1937 void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) {
1938         return EDGE_getLevelData(e) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1);
1939 }
1940 int ccgSubSurf_getEdgeNumFaces(CCGSubSurf *ss, CCGEdge *e) {
1941         return e->numFaces;
1942 }
1943 CCGFace *ccgSubSurf_getEdgeFace(CCGSubSurf *ss, CCGEdge *e, int index) {
1944         if (index<0 || index>=e->numFaces) {
1945                 return NULL;
1946         } else {
1947                 return e->faces[index];
1948         }
1949 }
1950 CCGVert *ccgSubSurf_getEdgeVert0(CCGSubSurf *ss, CCGEdge *e) {
1951         return e->v0;
1952 }
1953 CCGVert *ccgSubSurf_getEdgeVert1(CCGSubSurf *ss, CCGEdge *e) {
1954         return e->v1;
1955 }
1956 void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) {
1957         return ccgSubSurf_getEdgeData(ss, e, 0);
1958 }
1959 void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) {
1960         return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
1961 }
1962 void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) {
1963         if (level<0 || level>ss->subdivLevels) {
1964                 return NULL;
1965         } else {
1966                 return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
1967         }
1968 }
1969
1970 /* Face accessors */
1971
1972 CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGSubSurf *ss, CCGFace *f) {
1973         return f->fHDL;
1974 }
1975 int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) {
1976         if (ss->useAgeCounts) {
1977                 byte *userData = ccgSubSurf_getFaceUserData(ss, f);
1978                 return ss->currentAge - *((int*) &userData[ss->faceUserAgeOffset]);
1979         } else {
1980                 return 0;
1981         }
1982 }
1983 void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) {
1984         int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
1985         return FACE_getCenterData(f) + ss->meshIFC.vertDataSize *(1 + f->numVerts*maxGridSize + f->numVerts*maxGridSize*maxGridSize);
1986 }
1987 int ccgSubSurf_getFaceNumVerts(CCGSubSurf *ss, CCGFace *f) {
1988         return f->numVerts;
1989 }
1990 CCGVert *ccgSubSurf_getFaceVert(CCGSubSurf *ss, CCGFace *f, int index) {
1991         if (index<0 || index>=f->numVerts) {
1992                 return NULL;
1993         } else {
1994                 return FACE_getVerts(f)[index];
1995         }
1996 }
1997 CCGEdge *ccgSubSurf_getFaceEdge(CCGSubSurf *ss, CCGFace *f, int index) {
1998         if (index<0 || index>=f->numVerts) {
1999                 return NULL;
2000         } else {
2001                 return FACE_getEdges(f)[index];
2002         }
2003 }
2004 void *ccgSubSurf_getFaceCenterData(CCGSubSurf *ss, CCGFace *f) {
2005         return FACE_getCenterData(f);
2006 }
2007 void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
2008         return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
2009 }
2010 void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) {
2011         return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
2012 }
2013 void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
2014         return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
2015 }
2016 void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) {
2017         return _face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
2018 }
2019
2020 /*** External API iterator functions ***/
2021
2022 CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) {
2023         return (CCGVertIterator*) _ehashIterator_new(ss->vMap);
2024 }
2025 CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) {
2026         return (CCGEdgeIterator*) _ehashIterator_new(ss->eMap);
2027 }
2028 CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) {
2029         return (CCGFaceIterator*) _ehashIterator_new(ss->fMap);
2030 }
2031
2032 CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) {
2033         return (CCGVert*) _ehashIterator_getCurrent((EHashIterator*) vi);
2034 }
2035 int ccgVertIterator_isStopped(CCGVertIterator *vi) {
2036         return _ehashIterator_isStopped((EHashIterator*) vi);
2037 }
2038 void ccgVertIterator_next(CCGVertIterator *vi) {
2039         _ehashIterator_next((EHashIterator*) vi); 
2040 }
2041 void ccgVertIterator_free(CCGVertIterator *vi) {
2042         _ehashIterator_free((EHashIterator*) vi);
2043 }
2044
2045 CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) {
2046         return (CCGEdge*) _ehashIterator_getCurrent((EHashIterator*) vi);
2047 }
2048 int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) {
2049         return _ehashIterator_isStopped((EHashIterator*) vi);
2050 }
2051 void ccgEdgeIterator_next(CCGEdgeIterator *vi) {
2052         _ehashIterator_next((EHashIterator*) vi); 
2053 }
2054 void ccgEdgeIterator_free(CCGEdgeIterator *vi) {
2055         _ehashIterator_free((EHashIterator*) vi);
2056 }
2057
2058 CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) {
2059         return (CCGFace*) _ehashIterator_getCurrent((EHashIterator*) vi);
2060 }
2061 int ccgFaceIterator_isStopped(CCGFaceIterator *vi) {
2062         return _ehashIterator_isStopped((EHashIterator*) vi);
2063 }
2064 void ccgFaceIterator_next(CCGFaceIterator *vi) {
2065         _ehashIterator_next((EHashIterator*) vi); 
2066 }
2067 void ccgFaceIterator_free(CCGFaceIterator *vi) {
2068         _ehashIterator_free((EHashIterator*) vi);
2069 }
2070
2071 /*** Extern API final vert/edge/face interface ***/
2072
2073 int ccgSubSurf_getNumFinalVerts(CCGSubSurf *ss) {
2074         int edgeSize = 1 + (1<<ss->subdivLevels);
2075         int gridSize = 1 + (1<<(ss->subdivLevels-1));
2076         int numFinalVerts = ss->vMap->numEntries + ss->eMap->numEntries*(edgeSize-2) + ss->fMap->numEntries + ss->numGrids*((gridSize-2) + ((gridSize-2)*(gridSize-2)));
2077         return numFinalVerts;
2078 }
2079 int ccgSubSurf_getNumFinalEdges(CCGSubSurf *ss) {
2080         int edgeSize = 1 + (1<<ss->subdivLevels);
2081         int gridSize = 1 + (1<<(ss->subdivLevels-1));
2082         int numFinalEdges = ss->eMap->numEntries*(edgeSize-1) + ss->numGrids*((gridSize-1) + 2*((gridSize-2)*(gridSize-1)));
2083         return numFinalEdges;
2084 }
2085 int ccgSubSurf_getNumFinalFaces(CCGSubSurf *ss) {
2086         int gridSize = 1 + (1<<(ss->subdivLevels-1));
2087         int numFinalFaces = ss->numGrids*((gridSize-1)*(gridSize-1));
2088         return numFinalFaces;
2089 }