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