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