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