diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-07-20 16:05:16 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-07-20 23:29:25 +0300 |
commit | ccc3c2dbda36f00e74064e993d7e98bf8ab32a58 (patch) | |
tree | 43ac1a879558089e1cb7d6b7b7252fb91f711e76 /source | |
parent | 6190d75b5a8854f04c05cbd14a27837763fa5b95 (diff) |
CCGSubSurf: Split file into several smaller ones
This is a preparation commit for having OpenSubdiv integrated into Blender
and new layout is the following:
- CCGSubSurf.c contains implementation of common functions used by both
legacy subdivisions code and by the new code in the future.
- CCGSubSurf_inline.h contains internal functions which are to be inlined
due to the performance reasons. Those functions are only ment to be used
bu CCGSubSurf* files.
- CCGSubSurf_intern.h contains declarations of private functions and data
structures used by CCGSubSurf module.
- CCGSubSurf_legacy.c contains legacy implementation of subdivision algorithm.
- CCHSubSurf_util.c contains utility functions which are not directly related
on the subdivision code (i.e. debug functions, hash implementation etc).
There should be no functional changes so far.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf.c | 1827 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf_inline.h | 269 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf_intern.h | 277 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf_legacy.c | 1180 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf_util.c | 306 |
6 files changed, 2119 insertions, 1744 deletions
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 4f19c271d41..4b489a02459 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -61,6 +61,8 @@ set(INC_SYS set(SRC intern/CCGSubSurf.c + intern/CCGSubSurf_legacy.c + intern/CCGSubSurf_util.c intern/DerivedMesh.c intern/action.c intern/addon.c @@ -285,6 +287,8 @@ set(SRC nla_private.h tracking_private.h intern/CCGSubSurf.h + intern/CCGSubSurf_inline.h + intern/CCGSubSurf_intern.h intern/pbvh_intern.h intern/data_transfer_intern.h ) diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index cadca6b2623..a60e1fa3076 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -30,222 +30,17 @@ #include "BLI_sys_types.h" // for intptr_t support #include "BLI_utildefines.h" /* for BLI_assert */ +#include "BLI_math.h" #include "BKE_ccg.h" #include "CCGSubSurf.h" +#include "CCGSubSurf_intern.h" #include "BKE_subsurf.h" -/* used for normalize_v3 in BLI_math_vector - * float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */ -#define EPSILON (1.0e-35f) - -/* With this limit a single triangle becomes over 3 million faces */ -#define CCGSUBSURF_LEVEL_MAX 11 +#include "GL/glew.h" /***/ -typedef unsigned char byte; - -/***/ - -static int kHashSizes[] = { - 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, - 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, - 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 -}; - -typedef struct _EHEntry EHEntry; -struct _EHEntry { - EHEntry *next; - void *key; -}; -typedef struct _EHash { - EHEntry **buckets; - int numEntries, curSize, curSizeIdx; - - CCGAllocatorIFC allocatorIFC; - CCGAllocatorHDL allocator; -} EHash; - -#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb)) -#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr)) - -#define EHASH_hash(eh, item) (((uintptr_t) (item)) % ((unsigned int) (eh)->curSize)) - -static void ccgSubSurf__sync(CCGSubSurf *ss); -static int _edge_isBoundary(const CCGEdge *e); - -static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) -{ - EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh)); - eh->allocatorIFC = *allocatorIFC; - eh->allocator = allocator; - eh->numEntries = 0; - eh->curSizeIdx = 0; - while (kHashSizes[eh->curSizeIdx] < estimatedNumEntries) - eh->curSizeIdx++; - eh->curSize = kHashSizes[eh->curSizeIdx]; - eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); - memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); - - return eh; -} -typedef void (*EHEntryFreeFP)(EHEntry *, void *); -static void _ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) -{ - int numBuckets = eh->curSize; - - while (numBuckets--) { - EHEntry *entry = eh->buckets[numBuckets]; - - while (entry) { - EHEntry *next = entry->next; - - freeEntry(entry, userData); - - entry = next; - } - } - - EHASH_free(eh, eh->buckets); - EHASH_free(eh, eh); -} - -static void _ehash_insert(EHash *eh, EHEntry *entry) -{ - int numBuckets = eh->curSize; - int hash = EHASH_hash(eh, entry->key); - entry->next = eh->buckets[hash]; - eh->buckets[hash] = entry; - eh->numEntries++; - - if (UNLIKELY(eh->numEntries > (numBuckets * 3))) { - EHEntry **oldBuckets = eh->buckets; - eh->curSize = kHashSizes[++eh->curSizeIdx]; - - eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); - memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); - - while (numBuckets--) { - for (entry = oldBuckets[numBuckets]; entry; ) { - EHEntry *next = entry->next; - - hash = EHASH_hash(eh, entry->key); - entry->next = eh->buckets[hash]; - eh->buckets[hash] = entry; - - entry = next; - } - } - - EHASH_free(eh, oldBuckets); - } -} - -static void *_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) -{ - int hash = EHASH_hash(eh, key); - void **prevp = (void **) &eh->buckets[hash]; - EHEntry *entry; - - for (; (entry = *prevp); prevp = (void **) &entry->next) { - if (entry->key == key) { - *prevp_r = (void **) prevp; - return entry; - } - } - - return NULL; -} - -static void *_ehash_lookup(EHash *eh, void *key) -{ - int hash = EHASH_hash(eh, key); - EHEntry *entry; - - for (entry = eh->buckets[hash]; entry; entry = entry->next) - if (entry->key == key) - break; - - return entry; -} - -/**/ - -static void _ehashIterator_init(EHash *eh, EHashIterator *ehi) -{ - /* fill all members */ - ehi->eh = eh; - ehi->curBucket = -1; - ehi->curEntry = NULL; - - while (!ehi->curEntry) { - ehi->curBucket++; - if (ehi->curBucket == ehi->eh->curSize) - break; - ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } -} - -static void *_ehashIterator_getCurrent(EHashIterator *ehi) -{ - return ehi->curEntry; -} - -static void _ehashIterator_next(EHashIterator *ehi) -{ - if (ehi->curEntry) { - ehi->curEntry = ehi->curEntry->next; - while (!ehi->curEntry) { - ehi->curBucket++; - if (ehi->curBucket == ehi->eh->curSize) - break; - ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } - } -} -static int _ehashIterator_isStopped(EHashIterator *ehi) -{ - return !ehi->curEntry; -} - -/***/ - -static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) -{ - return MEM_mallocN(numBytes, "CCG standard alloc"); -} -static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a), void *ptr, int newSize, int UNUSED(oldSize)) -{ - return MEM_reallocN(ptr, newSize); -} -static void _stdAllocator_free(CCGAllocatorHDL UNUSED(a), void *ptr) -{ - MEM_freeN(ptr); -} - -static CCGAllocatorIFC *_getStandardAllocatorIFC(void) -{ - static CCGAllocatorIFC ifc; - - ifc.alloc = _stdAllocator_alloc; - ifc.realloc = _stdAllocator_realloc; - ifc.free = _stdAllocator_free; - ifc.release = NULL; - - return &ifc; -} - -/***/ - -BLI_INLINE int ccg_gridsize(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - - return (1 << (level - 1)) + 1; -} - int BKE_ccg_gridsize(int level) { return ccg_gridsize(level); @@ -259,240 +54,6 @@ int BKE_ccg_factor(int low_level, int high_level) return 1 << (high_level - low_level); } -BLI_INLINE int ccg_edgesize(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - - return 1 + (1 << level); -} - -BLI_INLINE int ccg_spacing(int high_level, int low_level) -{ - BLI_assert(high_level > 0 && low_level > 0); - BLI_assert(high_level >= low_level); - BLI_assert((high_level - low_level) <= CCGSUBSURF_LEVEL_MAX); - - return 1 << (high_level - low_level); -} - -BLI_INLINE int ccg_edgebase(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - - return level + (1 << level) - 1; -} - -/***/ - -#define NormZero(av) { float *_a = (float *) av; _a[0] = _a[1] = _a[2] = 0.0f; } (void)0 -#define NormCopy(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] = _b[0]; _a[1] = _b[1]; _a[2] = _b[2]; } (void)0 -#define NormAdd(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] += _b[0]; _a[1] += _b[1]; _a[2] += _b[2]; } (void)0 - -BLI_INLINE void Normalize(float no[3]) -{ - const float length = sqrtf(no[0] * no[0] + no[1] * no[1] + no[2] * no[2]); - - if (length > EPSILON) { - const float length_inv = 1.0f / length; - - no[0] *= length_inv; - no[1] *= length_inv; - no[2] *= length_inv; - } - else { - NormZero(no); - } -} - -/***/ - -enum { - Vert_eEffected = (1 << 0), - Vert_eChanged = (1 << 1), - Vert_eSeam = (1 << 2) -} /*VertFlags*/; -enum { - Edge_eEffected = (1 << 0) -} /*CCGEdgeFlags*/; -enum { - Face_eEffected = (1 << 0) -} /*FaceFlags*/; - -struct CCGVert { - CCGVert *next; /* EHData.next */ - CCGVertHDL vHDL; /* EHData.key */ - - short numEdges, numFaces, flags, pad; - - CCGEdge **edges; - CCGFace **faces; -// byte *levelData; -// byte *userData; -}; - -BLI_INLINE byte *VERT_getLevelData(CCGVert *v) -{ - return (byte *)(&(v)[1]); -} - -struct CCGEdge { - CCGEdge *next; /* EHData.next */ - CCGEdgeHDL eHDL; /* EHData.key */ - - short numFaces, flags; - float crease; - - CCGVert *v0, *v1; - CCGFace **faces; - -// byte *levelData; -// byte *userData; -}; - -BLI_INLINE byte *EDGE_getLevelData(CCGEdge *e) -{ - return (byte *)(&(e)[1]); -} - -struct CCGFace { - CCGFace *next; /* EHData.next */ - CCGFaceHDL fHDL; /* EHData.key */ - - short numVerts, flags, pad1, pad2; - -// CCGVert **verts; -// CCGEdge **edges; -// byte *centerData; -// byte **gridData; -// byte *userData; -}; - -BLI_INLINE CCGVert **FACE_getVerts(CCGFace *f) -{ - return (CCGVert **)(&f[1]); -} - -BLI_INLINE CCGEdge **FACE_getEdges(CCGFace *f) -{ - return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts])); -} - -BLI_INLINE byte *FACE_getCenterData(CCGFace *f) -{ - return (byte *)(&(FACE_getEdges(f)[(f)->numVerts])); -} - -typedef enum { - eSyncState_None = 0, - eSyncState_Vert, - eSyncState_Edge, - eSyncState_Face, - eSyncState_Partial -} SyncState; - -struct CCGSubSurf { - EHash *vMap; /* map of CCGVertHDL -> Vert */ - EHash *eMap; /* map of CCGEdgeHDL -> Edge */ - EHash *fMap; /* map of CCGFaceHDL -> Face */ - - CCGMeshIFC meshIFC; - - CCGAllocatorIFC allocatorIFC; - CCGAllocatorHDL allocator; - - int subdivLevels; - int numGrids; - int allowEdgeCreation; - float defaultCreaseValue; - void *defaultEdgeUserData; - - void *q, *r; - - /* data for calc vert normals */ - int calcVertNormals; - int normalDataOffset; - - /* data for paint masks */ - int allocMask; - int maskDataOffset; - - /* data for age'ing (to debug sync) */ - int currentAge; - int useAgeCounts; - int vertUserAgeOffset; - int edgeUserAgeOffset; - int faceUserAgeOffset; - - /* data used during syncing */ - SyncState syncState; - - EHash *oldVMap, *oldEMap, *oldFMap; - int lenTempArrays; - CCGVert **tempVerts; - CCGEdge **tempEdges; -}; - -#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb)) -#define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob)) -#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr)) - -/***/ - -static int VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) { - if (a[i] != b[i]) - return 0; - } - return 1; -} - -static void VertDataZero(float v[], const CCGSubSurf *ss) -{ - memset(v, 0, sizeof(float) * ss->meshIFC.numLayers); -} - -static void VertDataCopy(float dst[], const float src[], const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) - dst[i] = src[i]; -} - -static void VertDataAdd(float a[], const float b[], const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) - a[i] += b[i]; -} - -static void VertDataSub(float a[], const float b[], const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) - a[i] -= b[i]; -} - -static void VertDataMulN(float v[], float f, const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) - v[i] *= f; -} - -static void VertDataAvg4(float v[], - const float a[], const float b[], - const float c[], const float d[], - const CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->meshIFC.numLayers; i++) - v[i] = (a[i] + b[i] + c[i] + d[i]) * 0.25f; -} - /***/ static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss) @@ -559,24 +120,6 @@ static CCGEdge *_vert_findEdgeTo(const CCGVert *v, const CCGVert *vQ) } return NULL; } -static int _vert_isBoundary(const CCGVert *v) -{ - int i; - for (i = 0; i < v->numEdges; i++) - if (_edge_isBoundary(v->edges[i])) - return 1; - return 0; -} - -static void *_vert_getCo(CCGVert *v, int lvl, int dataSize) -{ - return &VERT_getLevelData(v)[lvl * dataSize]; -} -static float *_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) -{ - return (float *) &VERT_getLevelData(v)[lvl * dataSize + normalDataOffset]; -} - static void _vert_free(CCGVert *v, CCGSubSurf *ss) { if (v->edges) { @@ -590,11 +133,6 @@ static void _vert_free(CCGVert *v, CCGSubSurf *ss) CCGSUBSURF_free(ss, v); } -static int VERT_seam(const CCGVert *v) -{ - return ((v->flags & Vert_eSeam) != 0); -} - /***/ static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss) @@ -637,31 +175,6 @@ static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces)); e->faces[e->numFaces++] = f; } -static int _edge_isBoundary(const CCGEdge *e) -{ - return e->numFaces < 2; -} - -static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) -{ - if (vQ == e->v0) { - return e->v1; - } - else { - return e->v0; - } -} - -static void *_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) -{ - int levelBase = ccg_edgebase(lvl); - return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; -} -static float *_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset) -{ - int levelBase = ccg_edgebase(lvl); - return (float *) &EDGE_getLevelData(e)[dataSize * (levelBase + x) + normalDataOffset]; -} static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) { int levelBase = ccg_edgebase(lvl); @@ -690,18 +203,6 @@ static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) _edge_free(e, ss); } -static float EDGE_getSharpness(CCGEdge *e, int lvl) -{ - if (!lvl) - return e->crease; - else if (!e->crease) - return 0.0f; - else if (e->crease - lvl < 0.0f) - return 0.0f; - else - return e->crease - lvl; -} - static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss) { int maxGridSize = ccg_gridsize(ss->subdivLevels); @@ -733,102 +234,6 @@ static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int return f; } - -BLI_INLINE void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * x * spacing]; -} -BLI_INLINE void *_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * x * spacing + normalDataOffset]; -} -BLI_INLINE void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)]; -} -BLI_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return (float *) &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) + normalDataOffset]; -} -BLI_INLINE int _face_getVertIndex(CCGFace *f, CCGVert *v) -{ - int i; - for (i = 0; i < f->numVerts; i++) - if (FACE_getVerts(f)[i] == v) - return i; - return -1; -} -BLI_INLINE int _face_getEdgeIndex(CCGFace *f, CCGEdge *e) -{ - int i; - for (i = 0; i < f->numVerts; i++) - if (FACE_getEdges(f)[i] == e) - return i; - return -1; -} -BLI_INLINE void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - int x, y, cx, cy; - - BLI_assert(f_ed_idx == _face_getEdgeIndex(f, e)); - - eX = eX * spacing; - eY = eY * spacing; - if (e->v0 != FACE_getVerts(f)[f_ed_idx]) { - eX = (maxGridSize * 2 - 1) - 1 - eX; - } - y = maxGridSize - 1 - eX; - x = maxGridSize - 1 - eY; - if (x < 0) { - f_ed_idx = (f_ed_idx + f->numVerts - 1) % f->numVerts; - cx = y; - cy = -x; - } - else if (y < 0) { - f_ed_idx = (f_ed_idx + 1) % f->numVerts; - cx = -y; - cy = x; - } - else { - cx = x; - cy = y; - } - return _face_getIFCo(f, levels, f_ed_idx, cx, cy, levels, dataSize); -} -static float *_face_getIFNoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize, int normalDataOffset) -{ - return (float *) ((byte *) _face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) + normalDataOffset); -} -static void _face_calcIFNo(CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize) -{ - float *a = _face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize); - float *b = _face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize); - float *c = _face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize); - float *d = _face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize); - float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; - float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; - - no[0] = b_dY * a_cZ - b_dZ * a_cY; - no[1] = b_dZ * a_cX - b_dX * a_cZ; - no[2] = b_dX * a_cY - b_dY * a_cX; - - Normalize(no); -} - static void _face_free(CCGFace *f, CCGSubSurf *ss) { CCGSUBSURF_free(ss, f); @@ -849,7 +254,7 @@ static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) { if (!allocatorIFC) { - allocatorIFC = _getStandardAllocatorIFC(); + allocatorIFC = ccg_getStandardAllocatorIFC(); allocator = NULL; } @@ -862,9 +267,9 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a ss->allocatorIFC = *allocatorIFC; ss->allocator = allocator; - ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); ss->meshIFC = *ifc; @@ -904,9 +309,9 @@ void ccgSubSurf_free(CCGSubSurf *ss) CCGAllocatorHDL allocator = ss->allocator; if (ss->syncState) { - _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss); - _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss); - _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); + ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss); + ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss); + ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); MEM_freeN(ss->tempVerts); MEM_freeN(ss->tempEdges); @@ -916,9 +321,9 @@ void ccgSubSurf_free(CCGSubSurf *ss) CCGSUBSURF_free(ss, ss->q); if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData); - _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); - _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); - _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); + ccg_ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); + ccg_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); + ccg_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); CCGSUBSURF_free(ss, ss); @@ -963,12 +368,12 @@ CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) else if (subdivisionLevels != ss->subdivLevels) { ss->numGrids = 0; ss->subdivLevels = subdivisionLevels; - _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); - _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); - _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); - ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ccg_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss); + ccg_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss); + ccg_ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss); + ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); } return eCCGError_None; @@ -1051,9 +456,9 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) ss->oldEMap = ss->eMap; ss->oldFMap = ss->fMap; - ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); + ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); ss->numGrids = 0; @@ -1086,7 +491,7 @@ CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) } else { void **prevp; - CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); + CCGVert *v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); if (!v || v->numFaces || v->numEdges) { return eCCGError_InvalidValue; @@ -1107,7 +512,7 @@ CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) } else { void **prevp; - CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); + CCGEdge *e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); if (!e || e->numFaces) { return eCCGError_InvalidValue; @@ -1128,7 +533,7 @@ CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) } else { void **prevp; - CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); + CCGFace *f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); if (!f) { return eCCGError_InvalidValue; @@ -1149,19 +554,19 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertDa short seamflag = (seam) ? Vert_eSeam : 0; if (ss->syncState == eSyncState_Partial) { - v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); + v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp); if (!v) { v = _vert_new(vHDL, ss); - VertDataCopy(_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); - _ehash_insert(ss->vMap, (EHEntry *) v); + VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); + ccg_ehash_insert(ss->vMap, (EHEntry *) v); v->flags = Vert_eEffected | seamflag; } - else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) || + else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) || ((v->flags & Vert_eSeam) != seamflag)) { int i, j; - VertDataCopy(_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); + VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); v->flags = Vert_eEffected | seamflag; for (i = 0; i < v->numEdges; i++) { @@ -1182,24 +587,24 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertDa return eCCGError_InvalidSyncState; } - v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp); + v = ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp); if (!v) { v = _vert_new(vHDL, ss); - VertDataCopy(_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); - _ehash_insert(ss->vMap, (EHEntry *) v); + VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); + ccg_ehash_insert(ss->vMap, (EHEntry *) v); v->flags = Vert_eEffected | seamflag; } - else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) || + else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) || ((v->flags & Vert_eSeam) != seamflag)) { *prevp = v->next; - _ehash_insert(ss->vMap, (EHEntry *) v); - VertDataCopy(_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); + ccg_ehash_insert(ss->vMap, (EHEntry *) v); + VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss); v->flags = Vert_eEffected | Vert_eChanged | seamflag; } else { *prevp = v->next; - _ehash_insert(ss->vMap, (EHEntry *) v); + ccg_ehash_insert(ss->vMap, (EHEntry *) v); v->flags = 0; } } @@ -1214,10 +619,10 @@ CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0 CCGEdge *e = NULL, *eNew; if (ss->syncState == eSyncState_Partial) { - e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); + e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp); if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) { - CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0); - CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1); + CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0); + CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1); eNew = _edge_new(eHDL, v0, v1, crease, ss); @@ -1228,7 +633,7 @@ CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0 _edge_unlinkMarkAndFree(e, ss); } else { - _ehash_insert(ss->eMap, (EHEntry *) eNew); + ccg_ehash_insert(ss->eMap, (EHEntry *) eNew); } eNew->v0->flags |= Vert_eEffected; @@ -1243,18 +648,18 @@ CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0 return eCCGError_InvalidSyncState; } - e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp); + e = ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp); if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) { - CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0); - CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1); + CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0); + CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1); e = _edge_new(eHDL, v0, v1, crease, ss); - _ehash_insert(ss->eMap, (EHEntry *) e); + ccg_ehash_insert(ss->eMap, (EHEntry *) e); e->v0->flags |= Vert_eEffected; e->v1->flags |= Vert_eEffected; } else { *prevp = e->next; - _ehash_insert(ss->eMap, (EHEntry *) e); + ccg_ehash_insert(ss->eMap, (EHEntry *) e); e->flags = 0; if ((e->v0->flags | e->v1->flags) & Vert_eChanged) { e->v0->flags |= Vert_eEffected; @@ -1280,10 +685,10 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV } if (ss->syncState == eSyncState_Partial) { - f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); + f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp); for (k = 0; k < numVerts; k++) { - ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]); + ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]); } for (k = 0; k < numVerts; k++) { ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]); @@ -1311,7 +716,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV } else { ss->numGrids += numVerts; - _ehash_insert(ss->fMap, (EHEntry *) fNew); + ccg_ehash_insert(ss->fMap, (EHEntry *) fNew); } for (k = 0; k < numVerts; k++) @@ -1326,10 +731,10 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV return eCCGError_InvalidSyncState; } - f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp); + f = ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp); for (k = 0; k < numVerts; k++) { - ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]); + ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]); if (!ss->tempVerts[k]) return eCCGError_InvalidValue; @@ -1340,7 +745,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV if (!ss->tempEdges[k]) { if (ss->allowEdgeCreation) { CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) - 1, ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts], ss->defaultCreaseValue, ss); - _ehash_insert(ss->eMap, (EHEntry *) e); + ccg_ehash_insert(ss->eMap, (EHEntry *) e); e->v0->flags |= Vert_eEffected; e->v1->flags |= Vert_eEffected; if (ss->meshIFC.edgeUserSize) { @@ -1364,7 +769,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV if (!f || topologyChanged) { f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss); - _ehash_insert(ss->fMap, (EHEntry *) f); + ccg_ehash_insert(ss->fMap, (EHEntry *) f); ss->numGrids += numVerts; for (k = 0; k < numVerts; k++) @@ -1372,7 +777,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV } else { *prevp = f->next; - _ehash_insert(ss->fMap, (EHEntry *) f); + ccg_ehash_insert(ss->fMap, (EHEntry *) f); f->flags = 0; ss->numGrids += f->numVerts; @@ -1390,6 +795,11 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV return eCCGError_None; } +static void ccgSubSurf__sync(CCGSubSurf *ss) +{ + ccgSubSurf__sync_legacy(ss); +} + CCGError ccgSubSurf_processSync(CCGSubSurf *ss) { if (ss->syncState == eSyncState_Partial) { @@ -1398,9 +808,9 @@ CCGError ccgSubSurf_processSync(CCGSubSurf *ss) ccgSubSurf__sync(ss); } else if (ss->syncState) { - _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss); - _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss); - _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); + ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss); + ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss); + ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss); MEM_freeN(ss->tempEdges); MEM_freeN(ss->tempVerts); @@ -1421,1009 +831,7 @@ CCGError ccgSubSurf_processSync(CCGSubSurf *ss) return eCCGError_None; } -#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize) -#define VERT_getNo(e, lvl) _vert_getNo(v, lvl, vertDataSize, normalDataOffset) -#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize) -#define EDGE_getNo(e, lvl, x) _edge_getNo(e, lvl, x, vertDataSize, normalDataOffset) -#define FACE_getIFNo(f, lvl, S, x, y) _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset) -#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) -#define FACE_getIENo(f, lvl, S, x) _face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset) - -static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, - CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, - int numEffectedV, int numEffectedE, int numEffectedF) -{ - int i, ptrIdx; - int subdivLevels = ss->subdivLevels; - int lvl = ss->subdivLevels; - int edgeSize = ccg_edgesize(lvl); - int gridSize = ccg_gridsize(lvl); - int normalDataOffset = ss->normalDataOffset; - int vertDataSize = ss->meshIFC.vertDataSize; - -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - float no[3]; - - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, y)); - } - } - - if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); - } - } - if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { - for (y = 0; y < gridSize - 1; y++) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); - } - } - if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); - } - } - - for (S = 0; S < f->numVerts; S++) { - int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected); - int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected); - int yLimitNext = xLimit; - int xLimitPrev = yLimit; - - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int xPlusOk = (!xLimit || x < gridSize - 2); - int yPlusOk = (!yLimit || y < gridSize - 2); - - FACE_calcIFNo(f, lvl, S, x, y, no); - - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no); - if (xPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no); - if (yPlusOk) - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no); - if (xPlusOk && yPlusOk) { - if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) { - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no); - } - } - - if (x == 0 && y == 0) { - int K; - - if (!yLimitNext || 1 < gridSize - 1) - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no); - if (!xLimitPrev || 1 < gridSize - 1) - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no); - - for (K = 0; K < f->numVerts; K++) { - if (K != S) { - NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); - } - } - } - else if (y == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no); - if (!yLimitNext || x < gridSize - 2) - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no); - } - else if (x == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no); - if (!xLimitPrev || y < gridSize - 2) - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no); - } - } - } - } - } - /* XXX can I reduce the number of normalisations here? */ - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = (CCGVert *) effectedV[ptrIdx]; - float *no = VERT_getNo(v, lvl); - - NormZero(no); - - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f, v), gridSize - 1, gridSize - 1)); - } - - if (UNLIKELY(v->numFaces == 0)) { - NormCopy(no, VERT_getCo(v, lvl)); - } - - Normalize(no); - - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no); - } - } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; - - if (e->numFaces) { - CCGFace *fLast = e->faces[e->numFaces - 1]; - int x; - - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = _face_getEdgeIndex(f, e); - const int f_ed_idx_last = _face_getEdgeIndex(fLast, e); - - for (x = 1; x < edgeSize - 1; x++) { - NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = _face_getEdgeIndex(f, e); - const int f_ed_idx_last = _face_getEdgeIndex(fLast, e); - - for (x = 1; x < edgeSize - 1; x++) { - NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - } - } - -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - - for (S = 0; S < f->numVerts; S++) { - NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1), - FACE_getIFNo(f, lvl, S, gridSize - 1, 0)); - } - - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *no = FACE_getIFNo(f, lvl, S, x, y); - Normalize(no); - } - } - - VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset), - FACE_getIFNo(f, lvl, S, 0, 0), ss); - - for (x = 1; x < gridSize - 1; x++) - NormCopy(FACE_getIENo(f, lvl, S, x), - FACE_getIFNo(f, lvl, S, x, 0)); - } - } - - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; - - if (e->numFaces) { - CCGFace *f = e->faces[0]; - int x; - const int f_ed_idx = _face_getEdgeIndex(f, e); - - for (x = 0; x < edgeSize; x++) - NormCopy(EDGE_getNo(e, lvl, x), - _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - else { - /* set to zero here otherwise the normals are uninitialized memory - * render: tests/animation/knight.blend with valgrind. - * we could be more clever and interpolate vertex normals but these are - * most likely not used so just zero out. */ - int x; - - for (x = 0; x < edgeSize; x++) { - float *no = EDGE_getNo(e, lvl, x); - NormCopy(no, EDGE_getCo(e, lvl, x)); - Normalize(no); - } - } - } -} -#undef FACE_getIFNo - -#define FACE_getIECo(f, lvl, S, x) _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) -#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) - -static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss, - CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, - int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) -{ - int subdivLevels = ss->subdivLevels; - int edgeSize = ccg_edgesize(curLvl); - int gridSize = ccg_gridsize(curLvl); - int nextLvl = curLvl + 1; - int ptrIdx, cornerIdx, i; - int vertDataSize = ss->meshIFC.vertDataSize; - float *q = ss->q, *r = ss->r; - -#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - - /* interior face midpoints - * - old interior face points - */ - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = 1 + 2 * x; - int fy = 1 + 2 * y; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0); - const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1); - const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - } - - /* interior edge midpoints - * - old interior edge points - * - new interior face midpoints - */ - for (S = 0; S < f->numVerts; S++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = FACE_getIECo(f, curLvl, S, x + 0); - const float *co1 = FACE_getIECo(f, curLvl, S, x + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); - float *co = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - - /* interior face interior edge midpoints - * - old interior face points - * - new interior face midpoints - */ - - /* vertical */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 0; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2 + 1; - const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - - /* horizontal */ - for (y = 1; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = x * 2 + 1; - int fy = y * 2; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - } - } - - /* exterior edge midpoints - * - old exterior edge points - * - new interior face midpoints - */ - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); - int x, j; - - if (_edge_isBoundary(e) || sharpness > 1.0f) { - for (x = 0; x < edgeSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = EDGE_getCo(e, curLvl, x + 0); - const float *co1 = EDGE_getCo(e, curLvl, x + 1); - float *co = EDGE_getCo(e, nextLvl, fx); - - VertDataCopy(co, co0, ss); - VertDataAdd(co, co1, ss); - VertDataMulN(co, 0.5f, ss); - } - } - else { - for (x = 0; x < edgeSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = EDGE_getCo(e, curLvl, x + 0); - const float *co1 = EDGE_getCo(e, curLvl, x + 1); - float *co = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataCopy(q, co0, ss); - VertDataAdd(q, co1, ss); - - for (j = 0; j < e->numFaces; j++) { - CCGFace *f = e->faces[j]; - const int f_ed_idx = _face_getEdgeIndex(f, e); - VertDataAdd(q, _face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize), ss); - numFaces++; - } - - VertDataMulN(q, 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(r, co0, ss); - VertDataAdd(r, co1, ss); - VertDataMulN(r, 0.5f, ss); - - VertDataCopy(co, q, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, sharpness, ss); - VertDataAdd(co, r, ss); - } - } - } - - /* exterior vertex shift - * - old vertex points (shifting) - * - old exterior edge points - * - new interior face midpoints - */ - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = (CCGVert *) effectedV[ptrIdx]; - const float *co = VERT_getCo(v, curLvl); - float *nCo = VERT_getCo(v, nextLvl); - int sharpCount = 0, allSharp = 1; - float avgSharpness = 0.0; - int j, seam = VERT_seam(v), seamEdges = 0; - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam && _edge_isBoundary(e)) - seamEdges++; - - if (sharpness != 0.0f) { - sharpCount++; - avgSharpness += sharpness; - } - else { - allSharp = 0; - } - } - - if (sharpCount) { - avgSharpness /= sharpCount; - if (avgSharpness > 1.0f) { - avgSharpness = 1.0f; - } - } - - if (seamEdges < 2 || seamEdges != v->numEdges) - seam = 0; - - if (!v->numEdges || ss->meshIFC.simpleSubdiv) { - VertDataCopy(nCo, co, ss); - } - else if (_vert_isBoundary(v)) { - int numBoundary = 0; - - VertDataZero(r, ss); - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - if (_edge_isBoundary(e)) { - VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); - numBoundary++; - } - } - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, 0.75f, ss); - VertDataMulN(r, 0.25f / numBoundary, ss); - VertDataAdd(nCo, r, ss); - } - else { - int cornerIdx = (1 + (1 << (curLvl))) - 2; - int numEdges = 0, numFaces = 0; - - VertDataZero(q, ss); - for (j = 0; j < v->numFaces; j++) { - CCGFace *f = v->faces[j]; - VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f, v), cornerIdx, cornerIdx), ss); - numFaces++; - } - VertDataMulN(q, 1.0f / numFaces, ss); - VertDataZero(r, ss); - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); - numEdges++; - } - VertDataMulN(r, 1.0f / numEdges, ss); - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, numEdges - 2.0f, ss); - VertDataAdd(nCo, q, ss); - VertDataAdd(nCo, r, ss); - VertDataMulN(nCo, 1.0f / numEdges, ss); - } - - if ((sharpCount > 1 && v->numFaces) || seam) { - VertDataZero(q, ss); - - if (seam) { - avgSharpness = 1.0f; - sharpCount = seamEdges; - allSharp = 1; - } - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam) { - if (_edge_isBoundary(e)) - VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); - } - else if (sharpness != 0.0f) { - VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); - } - } - - VertDataMulN(q, (float) 1 / sharpCount, ss); - - if (sharpCount != 2 || allSharp) { - /* q = q + (co - q) * avgSharpness */ - VertDataCopy(r, co, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(q, r, ss); - } - - /* r = co * 0.75 + q * 0.25 */ - VertDataCopy(r, co, ss); - VertDataMulN(r, 0.75f, ss); - VertDataMulN(q, 0.25f, ss); - VertDataAdd(r, q, ss); - - /* nCo = nCo + (r - nCo) * avgSharpness */ - VertDataSub(r, nCo, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(nCo, r, ss); - } - } - - /* exterior edge interior shift - * - old exterior edge midpoints (shifting) - * - old exterior edge midpoints - * - new interior face midpoints - */ - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); - int sharpCount = 0; - float avgSharpness = 0.0; - int x, j; - - if (sharpness != 0.0f) { - sharpCount = 2; - avgSharpness += sharpness; - - if (avgSharpness > 1.0f) { - avgSharpness = 1.0f; - } - } - else { - sharpCount = 0; - avgSharpness = 0; - } - - if (_edge_isBoundary(e)) { - for (x = 1; x < edgeSize - 1; x++) { - int fx = x * 2; - const float *co = EDGE_getCo(e, curLvl, x); - float *nCo = EDGE_getCo(e, nextLvl, fx); - - /* Average previous level's endpoints */ - VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); - VertDataMulN(r, 0.5f, ss); - - /* nCo = nCo * 0.75 + r * 0.25 */ - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, 0.75f, ss); - VertDataMulN(r, 0.25f, ss); - VertDataAdd(nCo, r, ss); - } - } - else { - for (x = 1; x < edgeSize - 1; x++) { - int fx = x * 2; - const float *co = EDGE_getCo(e, curLvl, x); - float *nCo = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataZero(q, ss); - VertDataZero(r, ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); - for (j = 0; j < e->numFaces; j++) { - CCGFace *f = e->faces[j]; - int f_ed_idx = _face_getEdgeIndex(f, e); - VertDataAdd(q, _face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize), ss); - VertDataAdd(q, _face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize), ss); - - VertDataAdd(r, _face_getIFCoEdge(f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize), ss); - numFaces++; - } - VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss); - VertDataMulN(r, 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, (float) numFaces, ss); - VertDataAdd(nCo, q, ss); - VertDataAdd(nCo, r, ss); - VertDataMulN(nCo, 1.0f / (2 + numFaces), ss); - - if (sharpCount == 2) { - VertDataCopy(q, co, ss); - VertDataMulN(q, 6.0f, ss); - VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss); - VertDataMulN(q, 1 / 8.0f, ss); - - VertDataSub(q, nCo, ss); - VertDataMulN(q, avgSharpness, ss); - VertDataAdd(nCo, q, ss); - } - } - } - } - -#pragma omp parallel private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - { - float *q, *r; - -#pragma omp critical - { - q = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q"); - r = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r"); - } - -#pragma omp for schedule(static) - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = (CCGFace *) effectedF[ptrIdx]; - int S, x, y; - - /* interior center point shift - * - old face center point (shifting) - * - old interior edge points - * - new interior face midpoints - */ - VertDataZero(q, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1), ss); - } - VertDataMulN(q, 1.0f / f->numVerts, ss); - VertDataZero(r, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1), ss); - } - VertDataMulN(r, 1.0f / f->numVerts, ss); - - VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss); - VertDataAdd((float *)FACE_getCenterData(f), q, ss); - VertDataAdd((float *)FACE_getCenterData(f), r, ss); - VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); - - for (S = 0; S < f->numVerts; S++) { - /* interior face shift - * - old interior face point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 1; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2; - const float *co = FACE_getIFCo(f, curLvl, S, x, y); - float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(q, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1), - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1), - ss); - - VertDataAvg4(r, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r, ss); - } - } - - /* interior edge interior shift - * - old interior edge point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - int fx = x * 2; - const float *co = FACE_getIECo(f, curLvl, S, x); - float *nCo = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(q, - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, +1), - FACE_getIFCo(f, nextLvl, S, fx - 1, +1), ss); - - VertDataAvg4(r, - FACE_getIECo(f, nextLvl, S, fx - 1), - FACE_getIECo(f, nextLvl, S, fx + 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx), - FACE_getIFCo(f, nextLvl, S, fx, 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r, ss); - } - } - } - -#pragma omp critical - { - MEM_freeN(q); - MEM_freeN(r); - } - } - - /* copy down */ - edgeSize = ccg_edgesize(nextLvl); - gridSize = ccg_gridsize(nextLvl); - cornerIdx = gridSize - 1; - -#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); - VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss); - } - -#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - int S, x; - - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss); - for (x = 1; x < gridSize - 1; x++) { - float *co = FACE_getIECo(f, nextLvl, S, x); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss); - } - for (x = 0; x < gridSize - 1; x++) { - int eI = gridSize - 1 - x; - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); - } - } - } -} - - -static void ccgSubSurf__sync(CCGSubSurf *ss) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - CCGFace **effectedF; - int numEffectedV, numEffectedE, numEffectedF; - int subdivLevels = ss->subdivLevels; - int vertDataSize = ss->meshIFC.vertDataSize; - int i, j, ptrIdx, S; - int curLvl, nextLvl; - void *q = ss->q, *r = ss->r; - - effectedV = MEM_mallocN(sizeof(*effectedV) * ss->vMap->numEntries, "CCGSubsurf effectedV"); - effectedE = MEM_mallocN(sizeof(*effectedE) * ss->eMap->numEntries, "CCGSubsurf effectedE"); - effectedF = MEM_mallocN(sizeof(*effectedF) * ss->fMap->numEntries, "CCGSubsurf effectedF"); - numEffectedV = numEffectedE = numEffectedF = 0; - for (i = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *) ss->vMap->buckets[i]; - for (; v; v = v->next) { - if (v->flags & Vert_eEffected) { - effectedV[numEffectedV++] = v; - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - if (!(e->flags & Edge_eEffected)) { - effectedE[numEffectedE++] = e; - e->flags |= Edge_eEffected; - } - } - - for (j = 0; j < v->numFaces; j++) { - CCGFace *f = v->faces[j]; - if (!(f->flags & Face_eEffected)) { - effectedF[numEffectedF++] = f; - f->flags |= Face_eEffected; - } - } - } - } - } - - curLvl = 0; - nextLvl = curLvl + 1; - - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = effectedF[ptrIdx]; - void *co = FACE_getCenterData(f); - VertDataZero(co, ss); - for (i = 0; i < f->numVerts; i++) { - VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), ss); - } - VertDataMulN(co, 1.0f / f->numVerts, ss); - - f->flags = 0; - } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - void *co = EDGE_getCo(e, nextLvl, 1); - float sharpness = EDGE_getSharpness(e, curLvl); - - if (_edge_isBoundary(e) || sharpness >= 1.0f) { - VertDataCopy(co, VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(co, VERT_getCo(e->v1, curLvl), ss); - VertDataMulN(co, 0.5f, ss); - } - else { - int numFaces = 0; - VertDataCopy(q, VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(q, VERT_getCo(e->v1, curLvl), ss); - for (i = 0; i < e->numFaces; i++) { - CCGFace *f = e->faces[i]; - VertDataAdd(q, (float *)FACE_getCenterData(f), ss); - numFaces++; - } - VertDataMulN(q, 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(r, VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(r, VERT_getCo(e->v1, curLvl), ss); - VertDataMulN(r, 0.5f, ss); - - VertDataCopy(co, q, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, sharpness, ss); - VertDataAdd(co, r, ss); - } - - /* edge flags cleared later */ - } - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - void *co = VERT_getCo(v, curLvl); - void *nCo = VERT_getCo(v, nextLvl); - int sharpCount = 0, allSharp = 1; - float avgSharpness = 0.0; - int seam = VERT_seam(v), seamEdges = 0; - - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam && _edge_isBoundary(e)) - seamEdges++; - - if (sharpness != 0.0f) { - sharpCount++; - avgSharpness += sharpness; - } - else { - allSharp = 0; - } - } - - if (sharpCount) { - avgSharpness /= sharpCount; - if (avgSharpness > 1.0f) { - avgSharpness = 1.0f; - } - } - - if (seamEdges < 2 || seamEdges != v->numEdges) - seam = 0; - - if (!v->numEdges || ss->meshIFC.simpleSubdiv) { - VertDataCopy(nCo, co, ss); - } - else if (_vert_isBoundary(v)) { - int numBoundary = 0; - - VertDataZero(r, ss); - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - if (_edge_isBoundary(e)) { - VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); - numBoundary++; - } - } - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, 0.75f, ss); - VertDataMulN(r, 0.25f / numBoundary, ss); - VertDataAdd(nCo, r, ss); - } - else { - int numEdges = 0, numFaces = 0; - - VertDataZero(q, ss); - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - VertDataAdd(q, (float *)FACE_getCenterData(f), ss); - numFaces++; - } - VertDataMulN(q, 1.0f / numFaces, ss); - VertDataZero(r, ss); - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); - numEdges++; - } - VertDataMulN(r, 1.0f / numEdges, ss); - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, numEdges - 2.0f, ss); - VertDataAdd(nCo, q, ss); - VertDataAdd(nCo, r, ss); - VertDataMulN(nCo, 1.0f / numEdges, ss); - } - - if (sharpCount > 1 || seam) { - VertDataZero(q, ss); - - if (seam) { - avgSharpness = 1.0f; - sharpCount = seamEdges; - allSharp = 1; - } - - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam) { - if (_edge_isBoundary(e)) { - CCGVert *oV = _edge_getOtherVert(e, v); - VertDataAdd(q, VERT_getCo(oV, curLvl), ss); - } - } - else if (sharpness != 0.0f) { - CCGVert *oV = _edge_getOtherVert(e, v); - VertDataAdd(q, VERT_getCo(oV, curLvl), ss); - } - } - - VertDataMulN(q, (float) 1 / sharpCount, ss); - - if (sharpCount != 2 || allSharp) { - /* q = q + (co - q) * avgSharpness */ - VertDataCopy(r, co, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(q, r, ss); - } - - /* r = co * 0.75 + q * 0.25 */ - VertDataCopy(r, co, ss); - VertDataMulN(r, 0.75f, ss); - VertDataMulN(q, 0.25f, ss); - VertDataAdd(r, q, ss); - - /* nCo = nCo + (r - nCo) * avgSharpness */ - VertDataSub(r, nCo, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(nCo, r, ss); - } - - /* vert flags cleared later */ - } - - if (ss->useAgeCounts) { - for (i = 0; i < numEffectedV; i++) { - CCGVert *v = effectedV[i]; - byte *userData = ccgSubSurf_getVertUserData(ss, v); - *((int *) &userData[ss->vertUserAgeOffset]) = ss->currentAge; - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - byte *userData = ccgSubSurf_getEdgeUserData(ss, e); - *((int *) &userData[ss->edgeUserAgeOffset]) = ss->currentAge; - } - - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - byte *userData = ccgSubSurf_getFaceUserData(ss, f); - *((int *) &userData[ss->faceUserAgeOffset]) = ss->currentAge; - } - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); - VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss); - } - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss); - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss); - } - } - - for (curLvl = 1; curLvl < subdivLevels; curLvl++) { - ccgSubSurf__calcSubdivLevel(ss, - effectedV, effectedE, effectedF, - numEffectedV, numEffectedE, numEffectedF, curLvl); - } - - if (ss->calcVertNormals) - ccgSubSurf__calcVertNormals(ss, - effectedV, effectedE, effectedF, - numEffectedV, numEffectedE, numEffectedF); - - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - v->flags = 0; - } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - e->flags = 0; - } - - MEM_freeN(effectedF); - MEM_freeN(effectedE); - MEM_freeN(effectedV); -} - -static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces) +void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces) { CCGFace **array; int i, num; @@ -2447,7 +855,7 @@ static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces } } -static void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges) +void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges) { CCGVert **arrayV; CCGEdge **arrayE; @@ -2716,75 +1124,6 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in return eCCGError_None; } -/* update normals for specified faces */ -CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - int i, numEffectedV, numEffectedE, freeF; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, - &effectedV, &numEffectedV, &effectedE, &numEffectedE); - - if (ss->calcVertNormals) - ccgSubSurf__calcVertNormals(ss, - effectedV, effectedE, effectedF, - numEffectedV, numEffectedE, numEffectedF); - - for (i = 0; i < numEffectedV; i++) - effectedV[i]->flags = 0; - for (i = 0; i < numEffectedE; i++) - effectedE[i]->flags = 0; - for (i = 0; i < numEffectedF; i++) - effectedF[i]->flags = 0; - - MEM_freeN(effectedE); - MEM_freeN(effectedV); - if (freeF) MEM_freeN(effectedF); - - return eCCGError_None; -} - -/* compute subdivision levels from a given starting point, used by - * multires subdivide/propagate, by filling in coordinates at a - * certain level, and then subdividing that up to the highest level */ -CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - int numEffectedV, numEffectedE, freeF, i; - int curLvl, subdivLevels = ss->subdivLevels; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, - &effectedV, &numEffectedV, &effectedE, &numEffectedE); - - for (curLvl = lvl; curLvl < subdivLevels; curLvl++) { - ccgSubSurf__calcSubdivLevel(ss, - effectedV, effectedE, effectedF, - numEffectedV, numEffectedE, numEffectedF, curLvl); - } - - for (i = 0; i < numEffectedV; i++) - effectedV[i]->flags = 0; - for (i = 0; i < numEffectedE; i++) - effectedE[i]->flags = 0; - for (i = 0; i < numEffectedF; i++) - effectedF[i]->flags = 0; - - MEM_freeN(effectedE); - MEM_freeN(effectedV); - if (freeF) MEM_freeN(effectedF); - - return eCCGError_None; -} - -#undef VERT_getCo -#undef EDGE_getCo -#undef FACE_getIECo -#undef FACE_getIFCo - /*** External API accessor functions ***/ int ccgSubSurf_getNumVerts(const CCGSubSurf *ss) @@ -2802,15 +1141,15 @@ int ccgSubSurf_getNumFaces(const CCGSubSurf *ss) CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) { - return (CCGVert *) _ehash_lookup(ss->vMap, v); + return (CCGVert *) ccg_ehash_lookup(ss->vMap, v); } CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) { - return (CCGEdge *) _ehash_lookup(ss->eMap, e); + return (CCGEdge *) ccg_ehash_lookup(ss->eMap, e); } CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) { - return (CCGFace *) _ehash_lookup(ss->fMap, f); + return (CCGFace *) ccg_ehash_lookup(ss->fMap, f); } int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss) @@ -2905,7 +1244,7 @@ void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) return NULL; } else { - return _vert_getCo(v, level, ss->meshIFC.vertDataSize); + return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize); } } @@ -2965,7 +1304,7 @@ void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) return NULL; } else { - return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize); + return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize); } } float ccgSubSurf_getEdgeCrease(CCGEdge *e) @@ -3037,7 +1376,7 @@ void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIn } void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) { - return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize); + return ccg_face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize); } void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) { @@ -3045,61 +1384,61 @@ void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) } void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) { - return _face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize); + return ccg_face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize); } /*** External API iterator functions ***/ void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter) { - _ehashIterator_init(ss->vMap, viter); + ccg_ehashIterator_init(ss->vMap, viter); } void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter) { - _ehashIterator_init(ss->eMap, eiter); + ccg_ehashIterator_init(ss->eMap, eiter); } void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter) { - _ehashIterator_init(ss->fMap, fiter); + ccg_ehashIterator_init(ss->fMap, fiter); } CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) { - return (CCGVert *) _ehashIterator_getCurrent((EHashIterator *) vi); + return (CCGVert *) ccg_ehashIterator_getCurrent((EHashIterator *) vi); } int ccgVertIterator_isStopped(CCGVertIterator *vi) { - return _ehashIterator_isStopped((EHashIterator *) vi); + return ccg_ehashIterator_isStopped((EHashIterator *) vi); } void ccgVertIterator_next(CCGVertIterator *vi) { - _ehashIterator_next((EHashIterator *) vi); + ccg_ehashIterator_next((EHashIterator *) vi); } CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) { - return (CCGEdge *) _ehashIterator_getCurrent((EHashIterator *) vi); + return (CCGEdge *) ccg_ehashIterator_getCurrent((EHashIterator *) vi); } int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) { - return _ehashIterator_isStopped((EHashIterator *) vi); + return ccg_ehashIterator_isStopped((EHashIterator *) vi); } void ccgEdgeIterator_next(CCGEdgeIterator *vi) { - _ehashIterator_next((EHashIterator *) vi); + ccg_ehashIterator_next((EHashIterator *) vi); } CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) { - return (CCGFace *) _ehashIterator_getCurrent((EHashIterator *) vi); + return (CCGFace *) ccg_ehashIterator_getCurrent((EHashIterator *) vi); } int ccgFaceIterator_isStopped(CCGFaceIterator *vi) { - return _ehashIterator_isStopped((EHashIterator *) vi); + return ccg_ehashIterator_isStopped((EHashIterator *) vi); } void ccgFaceIterator_next(CCGFaceIterator *vi) { - _ehashIterator_next((EHashIterator *) vi); + ccg_ehashIterator_next((EHashIterator *) vi); } /*** Extern API final vert/edge/face interface ***/ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_inline.h b/source/blender/blenkernel/intern/CCGSubSurf_inline.h new file mode 100644 index 00000000000..183578c26ce --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf_inline.h @@ -0,0 +1,269 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/CCGSubSurf_inline.h + * \ingroup bke + */ + +#ifndef __CCGSUBSURF_INLINE_H__ +#define __CCGSUBSURF_INLINE_H__ + +BLI_INLINE int ccg_gridsize(int level) +{ + BLI_assert(level > 0); + BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); + return (1 << (level - 1)) + 1; +} + +BLI_INLINE int ccg_edgesize(int level) +{ + BLI_assert(level > 0); + BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); + return 1 + (1 << level); +} + +BLI_INLINE int ccg_spacing(int high_level, int low_level) +{ + BLI_assert(high_level > 0 && low_level > 0); + BLI_assert(high_level >= low_level); + BLI_assert((high_level - low_level) <= CCGSUBSURF_LEVEL_MAX); + return 1 << (high_level - low_level); +} + +BLI_INLINE int ccg_edgebase(int level) +{ + BLI_assert(level > 0); + BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); + return level + (1 << level) - 1; +} + +/* **** */ + +BLI_INLINE byte *VERT_getLevelData(CCGVert *v) +{ + return (byte *)(&(v)[1]); +} + +BLI_INLINE byte *EDGE_getLevelData(CCGEdge *e) +{ + return (byte *)(&(e)[1]); +} + +BLI_INLINE CCGVert **FACE_getVerts(CCGFace *f) +{ + return (CCGVert **)(&f[1]); +} + +BLI_INLINE CCGEdge **FACE_getEdges(CCGFace *f) +{ + return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts])); +} + +BLI_INLINE byte *FACE_getCenterData(CCGFace *f) +{ + return (byte *)(&(FACE_getEdges(f)[(f)->numVerts])); +} + +/* **** */ + +BLI_INLINE void *ccg_vert_getCo(CCGVert *v, int lvl, int dataSize) +{ + return &VERT_getLevelData(v)[lvl * dataSize]; +} + +BLI_INLINE float *ccg_vert_getNo(CCGVert *v, + int lvl, + int dataSize, + int normalDataOffset) +{ + return (float *) &VERT_getLevelData(v)[lvl * dataSize + normalDataOffset]; +} + +BLI_INLINE void *ccg_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) +{ + int levelBase = ccg_edgebase(lvl); + return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; +} + +BLI_INLINE float *ccg_edge_getNo(CCGEdge *e, + int lvl, + int x, + int dataSize, + int normalDataOffset) +{ + int levelBase = ccg_edgebase(lvl); + return (float *) &EDGE_getLevelData(e)[dataSize * (levelBase + x) + normalDataOffset]; +} + +BLI_INLINE void *ccg_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) +{ + int maxGridSize = ccg_gridsize(levels); + int spacing = ccg_spacing(levels, lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); + return &gridBase[dataSize * x * spacing]; +} + +BLI_INLINE void *ccg_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) +{ + int maxGridSize = ccg_gridsize(levels); + int spacing = ccg_spacing(levels, lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); + return &gridBase[dataSize * x * spacing + normalDataOffset]; +} + +BLI_INLINE void *ccg_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) +{ + int maxGridSize = ccg_gridsize(levels); + int spacing = ccg_spacing(levels, lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); + return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)]; +} + +BLI_INLINE float *ccg_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) +{ + int maxGridSize = ccg_gridsize(levels); + int spacing = ccg_spacing(levels, lvl); + byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); + return (float *) &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) + normalDataOffset]; +} + + +BLI_INLINE int ccg_face_getVertIndex(CCGFace *f, CCGVert *v) +{ + int i; + for (i = 0; i < f->numVerts; i++) + if (FACE_getVerts(f)[i] == v) + return i; + return -1; +} + +BLI_INLINE int ccg_face_getEdgeIndex(CCGFace *f, CCGEdge *e) +{ + int i; + for (i = 0; i < f->numVerts; i++) + if (FACE_getEdges(f)[i] == e) + return i; + return -1; +} + +BLI_INLINE void *ccg_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize) +{ + int maxGridSize = ccg_gridsize(levels); + int spacing = ccg_spacing(levels, lvl); + int x, y, cx, cy; + + BLI_assert(f_ed_idx == ccg_face_getEdgeIndex(f, e)); + + eX = eX * spacing; + eY = eY * spacing; + if (e->v0 != FACE_getVerts(f)[f_ed_idx]) { + eX = (maxGridSize * 2 - 1) - 1 - eX; + } + y = maxGridSize - 1 - eX; + x = maxGridSize - 1 - eY; + if (x < 0) { + f_ed_idx = (f_ed_idx + f->numVerts - 1) % f->numVerts; + cx = y; + cy = -x; + } + else if (y < 0) { + f_ed_idx = (f_ed_idx + 1) % f->numVerts; + cx = -y; + cy = x; + } + else { + cx = x; + cy = y; + } + return ccg_face_getIFCo(f, levels, f_ed_idx, cx, cy, levels, dataSize); +} + +BLI_INLINE void Normalize(float no[3]) +{ + const float length = sqrtf(no[0] * no[0] + no[1] * no[1] + no[2] * no[2]); + + if (length > EPSILON) { + const float length_inv = 1.0f / length; + + no[0] *= length_inv; + no[1] *= length_inv; + no[2] *= length_inv; + } + else { + NormZero(no); + } +} + +/* Data layers mathematics. */ + +BLI_INLINE int VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) { + if (a[i] != b[i]) + return 0; + } + return 1; +} + +BLI_INLINE void VertDataZero(float v[], const CCGSubSurf *ss) +{ + memset(v, 0, sizeof(float) * ss->meshIFC.numLayers); +} + +BLI_INLINE void VertDataCopy(float dst[], const float src[], const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) + dst[i] = src[i]; +} + +BLI_INLINE void VertDataAdd(float a[], const float b[], const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) + a[i] += b[i]; +} + +BLI_INLINE void VertDataSub(float a[], const float b[], const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) + a[i] -= b[i]; +} + +BLI_INLINE void VertDataMulN(float v[], float f, const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) + v[i] *= f; +} + +BLI_INLINE void VertDataAvg4(float v[], + const float a[], const float b[], + const float c[], const float d[], + const CCGSubSurf *ss) +{ + int i; + for (i = 0; i < ss->meshIFC.numLayers; i++) + v[i] = (a[i] + b[i] + c[i] + d[i]) * 0.25f; +} + +#endif /* __CCGSUBSURF_INLINE_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h new file mode 100644 index 00000000000..1689ac482ef --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -0,0 +1,277 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/CCGSubSurf_intern.h + * \ingroup bke + */ + +#ifndef __CCGSUBSURF_INTERN_H__ +#define __CCGSUBSURF_INTERN_H__ + +/** + * Definitions which defines internal behavior of CCGSubSurf. + */ + +/* Define this to see dump of the grids after the subsurf applied. */ +#undef DUMP_RESULT_GRIDS + +/* used for normalize_v3 in BLI_math_vector + * float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */ +#define EPSILON (1.0e-35f) + +/* With this limit a single triangle becomes over 3 million faces */ +#define CCGSUBSURF_LEVEL_MAX 11 + +/** + * Common type definitions. + */ + +typedef unsigned char byte; + +/** + * Hash implementation. + */ + +typedef struct _EHEntry { + struct _EHEntry *next; + void *key; +} EHEntry; + +typedef struct _EHash { + EHEntry **buckets; + int numEntries, curSize, curSizeIdx; + + CCGAllocatorIFC allocatorIFC; + CCGAllocatorHDL allocator; +} EHash; + +typedef void (*EHEntryFreeFP)(EHEntry *, void *); + +#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb)) +#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr)) +#define EHASH_hash(eh, item) (((uintptr_t) (item)) % ((unsigned int) (eh)->curSize)) + +/* Generic hash functions. */ + +EHash *ccg_ehash_new(int estimatedNumEntries, + CCGAllocatorIFC *allocatorIFC, + CCGAllocatorHDL allocator); +void ccg_ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData); +void ccg_ehash_insert(EHash *eh, EHEntry *entry); +void *ccg_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r); +void *ccg_ehash_lookup(EHash *eh, void *key); + +/* Hash elements iteration. */ + +void ccg_ehashIterator_init(EHash *eh, EHashIterator *ehi); +void *ccg_ehashIterator_getCurrent(EHashIterator *ehi); +void ccg_ehashIterator_next(EHashIterator *ehi); +int ccg_ehashIterator_isStopped(EHashIterator *ehi); + +/** + * Standard allocator implementarion. + */ + +CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void); + +/** + * Catmull-Clark Gridding Subdivision Surface. + */ + +/* TODO(sergey): Get rid of this, it's more or less a bad level call. */ +struct DerivedMesh; + +/* ** Data structures, constants. enums ** */ + +enum { + Vert_eEffected = (1 << 0), + Vert_eChanged = (1 << 1), + Vert_eSeam = (1 << 2) +} /*VertFlags*/; + +enum { + Edge_eEffected = (1 << 0) +} /*CCGEdgeFlags*/; + +enum { + Face_eEffected = (1 << 0) +} /*FaceFlags*/; + +struct CCGVert { + CCGVert *next; /* EHData.next */ + CCGVertHDL vHDL; /* EHData.key */ + + short numEdges, numFaces, flags; + int osd_index; /* Index of the vertex in the map, used by OSD. */ + + CCGEdge **edges; + CCGFace **faces; + /* byte *levelData; */ + /* byte *userData; */ +}; + +struct CCGEdge { + CCGEdge *next; /* EHData.next */ + CCGEdgeHDL eHDL; /* EHData.key */ + + short numFaces, flags; + float crease; + + CCGVert *v0, *v1; + CCGFace **faces; + + /* byte *levelData; */ + /* byte *userData; */ +}; + +struct CCGFace { + CCGFace *next; /* EHData.next */ + CCGFaceHDL fHDL; /* EHData.key */ + + short numVerts, flags; + int osd_index; + + /* CCGVert **verts; */ + /* CCGEdge **edges; */ + /* byte *centerData; */ + /* byte **gridData; */ + /* byte *userData; */ +}; + +typedef enum { + eSyncState_None = 0, + eSyncState_Vert, + eSyncState_Edge, + eSyncState_Face, + eSyncState_Partial, +} SyncState; + +struct CCGSubSurf { + EHash *vMap; /* map of CCGVertHDL -> Vert */ + EHash *eMap; /* map of CCGEdgeHDL -> Edge */ + EHash *fMap; /* map of CCGFaceHDL -> Face */ + + CCGMeshIFC meshIFC; + + CCGAllocatorIFC allocatorIFC; + CCGAllocatorHDL allocator; + + int subdivLevels; + int numGrids; + int allowEdgeCreation; + float defaultCreaseValue; + void *defaultEdgeUserData; + + void *q, *r; + + /* Data for calc vert normals. */ + int calcVertNormals; + int normalDataOffset; + + /* Data for paint masks. */ + int allocMask; + int maskDataOffset; + + /* Data for age'ing (to debug sync). */ + int currentAge; + int useAgeCounts; + int vertUserAgeOffset; + int edgeUserAgeOffset; + int faceUserAgeOffset; + + /* Data used during syncing. */ + SyncState syncState; + + EHash *oldVMap, *oldEMap, *oldFMap; + int lenTempArrays; + CCGVert **tempVerts; + CCGEdge **tempEdges; +}; + +/* ** Utility macros ** */ + +#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb)) +#define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob)) +#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr)) + +#define VERT_getCo(v, lvl) ccg_vert_getCo(v, lvl, vertDataSize) +#define VERT_getNo(v, lvl) ccg_vert_getNo(v, lvl, vertDataSize, normalDataOffset) +#define EDGE_getCo(e, lvl, x) ccg_edge_getCo(e, lvl, x, vertDataSize) +#define EDGE_getNo(e, lvl, x) ccg_edge_getNo(e, lvl, x, vertDataSize, normalDataOffset) +#define FACE_getIFNo(f, lvl, S, x, y) ccg_face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset) +//#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) +#define FACE_getIENo(f, lvl, S, x) ccg_face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset) +#define FACE_getIECo(f, lvl, S, x) ccg_face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) +#define FACE_getIFCo(f, lvl, S, x, y) ccg_face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) + +#define NormZero(av) { float *_a = (float *) av; _a[0] = _a[1] = _a[2] = 0.0f; } (void)0 +#define NormCopy(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] = _b[0]; _a[1] = _b[1]; _a[2] = _b[2]; } (void)0 +#define NormAdd(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] += _b[0]; _a[1] += _b[1]; _a[2] += _b[2]; } (void)0 + +/* ** General purpose functions ** */ + +/* * CCGSubSurf.c * */ + +void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces); +void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, + CCGFace **faces, + int numFaces, + CCGVert ***verts, + int *numVerts, + CCGEdge ***edges, + int *numEdges); + +/* * CCGSubSurf_legacy.c * */ + +void ccgSubSurf__sync_legacy(CCGSubSurf *ss); + +/* * CCGSubSurf_opensubdiv.c * */ + +void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss); + +int ccgSubSurf__getNumOsdBaseVerts(const CCGSubSurf *ss); +int ccgSubSurf__getNumOsdBaseEdges(const CCGSubSurf *ss); +int ccgSubSurf__getNumOsdBaseFaces(const CCGSubSurf *ss); + +/* * CCGSubSurf_opensubdiv_converter.c * */ + +struct OpenSubdiv_Converter; + +void ccgSubSurf_converter_setup_from_derivedmesh( + CCGSubSurf *ss, + struct DerivedMesh *dm, + struct OpenSubdiv_Converter *converter); + +void ccgSubSurf_converter_setup_from_ccg( + CCGSubSurf *ss, + struct OpenSubdiv_Converter *converter); + +void ccgSubSurf_converter_free( + struct OpenSubdiv_Converter *converter); + +/* * CCGSubSurf_util.c * */ + +#ifdef DUMP_RESULT_GRIDS +void ccgSubSurf__dumpCoords(CCGSubSurf *ss); +#endif + +#include "CCGSubSurf_inline.h" + +#endif /* __CCGSUBSURF_INTERN_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c new file mode 100644 index 00000000000..6adef1ca729 --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c @@ -0,0 +1,1180 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/CCGSubSurf_legacy.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" +#include "BLI_sys_types.h" // for intptr_t support + +#include "BLI_utildefines.h" /* for BLI_assert */ +#include "BLI_math.h" + +#include "CCGSubSurf.h" +#include "CCGSubSurf_intern.h" + +#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) + +/* TODO(sergey): Deduplicate the following functions/ */ +static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) +{ + int levelBase = ccg_edgebase(lvl); + if (v == e->v0) { + return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; + } + else { + return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)]; + } +} +/* *************************************************** */ + +static int _edge_isBoundary(const CCGEdge *e) +{ + return e->numFaces < 2; +} + +static int _vert_isBoundary(const CCGVert *v) +{ + int i; + for (i = 0; i < v->numEdges; i++) + if (_edge_isBoundary(v->edges[i])) + return 1; + return 0; +} + +static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) +{ + if (vQ == e->v0) { + return e->v1; + } + else { + return e->v0; + } +} + +static float *_face_getIFNoEdge(CCGFace *f, + CCGEdge *e, + int f_ed_idx, + int lvl, + int eX, int eY, + int levels, + int dataSize, + int normalDataOffset) +{ + return (float *) ((byte *) ccg_face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) + normalDataOffset); +} + +static void _face_calcIFNo(CCGFace *f, + int lvl, + int S, + int x, int y, + float no[3], + int levels, + int dataSize) +{ + float *a = ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize); + float *b = ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize); + float *c = ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize); + float *d = ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize); + float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; + float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; + + no[0] = b_dY * a_cZ - b_dZ * a_cY; + no[1] = b_dZ * a_cX - b_dX * a_cZ; + no[2] = b_dX * a_cY - b_dY * a_cX; + + Normalize(no); +} + +static int VERT_seam(const CCGVert *v) +{ + return ((v->flags & Vert_eSeam) != 0); +} + +static float EDGE_getSharpness(CCGEdge *e, int lvl) +{ + if (!lvl) + return e->crease; + else if (!e->crease) + return 0.0f; + else if (e->crease - lvl < 0.0f) + return 0.0f; + else + return e->crease - lvl; +} + +static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + int numEffectedV, int numEffectedE, int numEffectedF) +{ + int i, ptrIdx; + int subdivLevels = ss->subdivLevels; + int lvl = ss->subdivLevels; + int edgeSize = ccg_edgesize(lvl); + int gridSize = ccg_gridsize(lvl); + int normalDataOffset = ss->normalDataOffset; + int vertDataSize = ss->meshIFC.vertDataSize; + +#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace *) effectedF[ptrIdx]; + int S, x, y; + float no[3]; + + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + NormZero(FACE_getIFNo(f, lvl, S, x, y)); + } + } + + if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { + for (x = 0; x < gridSize - 1; x++) { + NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); + } + } + if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { + for (y = 0; y < gridSize - 1; y++) { + NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); + } + } + if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { + NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); + } + } + + for (S = 0; S < f->numVerts; S++) { + int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected); + int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected); + int yLimitNext = xLimit; + int xLimitPrev = yLimit; + + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + int xPlusOk = (!xLimit || x < gridSize - 2); + int yPlusOk = (!yLimit || y < gridSize - 2); + + FACE_calcIFNo(f, lvl, S, x, y, no); + + NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no); + if (xPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no); + if (yPlusOk) + NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no); + if (xPlusOk && yPlusOk) { + if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) { + NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no); + } + } + + if (x == 0 && y == 0) { + int K; + + if (!yLimitNext || 1 < gridSize - 1) + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no); + if (!xLimitPrev || 1 < gridSize - 1) + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no); + + for (K = 0; K < f->numVerts; K++) { + if (K != S) { + NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); + } + } + } + else if (y == 0) { + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no); + if (!yLimitNext || x < gridSize - 2) + NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no); + } + else if (x == 0) { + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no); + if (!xLimitPrev || y < gridSize - 2) + NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no); + } + } + } + } + } + /* XXX can I reduce the number of normalisations here? */ + for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { + CCGVert *v = (CCGVert *) effectedV[ptrIdx]; + float *no = VERT_getNo(v, lvl); + + NormZero(no); + + for (i = 0; i < v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1)); + } + + if (UNLIKELY(v->numFaces == 0)) { + NormCopy(no, VERT_getCo(v, lvl)); + } + + Normalize(no); + + for (i = 0; i < v->numFaces; i++) { + CCGFace *f = v->faces[i]; + NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no); + } + } + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; + + if (e->numFaces) { + CCGFace *fLast = e->faces[e->numFaces - 1]; + int x; + + for (i = 0; i < e->numFaces - 1; i++) { + CCGFace *f = e->faces[i]; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); + + for (x = 1; x < edgeSize - 1; x++) { + NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); + } + } + + for (i = 0; i < e->numFaces - 1; i++) { + CCGFace *f = e->faces[i]; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); + + for (x = 1; x < edgeSize - 1; x++) { + NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), + _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); + } + } + } + } + +#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace *) effectedF[ptrIdx]; + int S, x, y; + + for (S = 0; S < f->numVerts; S++) { + NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1), + FACE_getIFNo(f, lvl, S, gridSize - 1, 0)); + } + + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize; y++) { + for (x = 0; x < gridSize; x++) { + float *no = FACE_getIFNo(f, lvl, S, x, y); + Normalize(no); + } + } + + VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset), + FACE_getIFNo(f, lvl, S, 0, 0), ss); + + for (x = 1; x < gridSize - 1; x++) + NormCopy(FACE_getIENo(f, lvl, S, x), + FACE_getIFNo(f, lvl, S, x, 0)); + } + } + + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; + + if (e->numFaces) { + CCGFace *f = e->faces[0]; + int x; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + + for (x = 0; x < edgeSize; x++) + NormCopy(EDGE_getNo(e, lvl, x), + _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); + } + else { + /* set to zero here otherwise the normals are uninitialized memory + * render: tests/animation/knight.blend with valgrind. + * we could be more clever and interpolate vertex normals but these are + * most likely not used so just zero out. */ + int x; + + for (x = 0; x < edgeSize; x++) { + float *no = EDGE_getNo(e, lvl, x); + NormCopy(no, EDGE_getCo(e, lvl, x)); + Normalize(no); + } + } + } +} + +static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss, + CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF, + int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) +{ + int subdivLevels = ss->subdivLevels; + int edgeSize = ccg_edgesize(curLvl); + int gridSize = ccg_gridsize(curLvl); + int nextLvl = curLvl + 1; + int ptrIdx, cornerIdx, i; + int vertDataSize = ss->meshIFC.vertDataSize; + float *q = ss->q, *r = ss->r; + +#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace *) effectedF[ptrIdx]; + int S, x, y; + + /* interior face midpoints + * - old interior face points + */ + for (S = 0; S < f->numVerts; S++) { + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + int fx = 1 + 2 * x; + int fy = 1 + 2 * y; + const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0); + const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0); + const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1); + const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + } + } + + /* interior edge midpoints + * - old interior edge points + * - new interior face midpoints + */ + for (S = 0; S < f->numVerts; S++) { + for (x = 0; x < gridSize - 1; x++) { + int fx = x * 2 + 1; + const float *co0 = FACE_getIECo(f, curLvl, S, x + 0); + const float *co1 = FACE_getIECo(f, curLvl, S, x + 1); + const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); + float *co = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + + /* interior face interior edge midpoints + * - old interior face points + * - new interior face midpoints + */ + + /* vertical */ + for (x = 1; x < gridSize - 1; x++) { + for (y = 0; y < gridSize - 1; y++) { + int fx = x * 2; + int fy = y * 2 + 1; + const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0); + const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1); + const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + } + + /* horizontal */ + for (y = 1; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { + int fx = x * 2 + 1; + int fy = y * 2; + const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y); + const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y); + const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1); + const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1); + float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(co, co0, co1, co2, co3, ss); + } + } + } + } + + /* exterior edge midpoints + * - old exterior edge points + * - new interior face midpoints + */ + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; + float sharpness = EDGE_getSharpness(e, curLvl); + int x, j; + + if (_edge_isBoundary(e) || sharpness > 1.0f) { + for (x = 0; x < edgeSize - 1; x++) { + int fx = x * 2 + 1; + const float *co0 = EDGE_getCo(e, curLvl, x + 0); + const float *co1 = EDGE_getCo(e, curLvl, x + 1); + float *co = EDGE_getCo(e, nextLvl, fx); + + VertDataCopy(co, co0, ss); + VertDataAdd(co, co1, ss); + VertDataMulN(co, 0.5f, ss); + } + } + else { + for (x = 0; x < edgeSize - 1; x++) { + int fx = x * 2 + 1; + const float *co0 = EDGE_getCo(e, curLvl, x + 0); + const float *co1 = EDGE_getCo(e, curLvl, x + 1); + float *co = EDGE_getCo(e, nextLvl, fx); + int numFaces = 0; + + VertDataCopy(q, co0, ss); + VertDataAdd(q, co1, ss); + + for (j = 0; j < e->numFaces; j++) { + CCGFace *f = e->faces[j]; + const int f_ed_idx = ccg_face_getEdgeIndex(f, e); + VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize), ss); + numFaces++; + } + + VertDataMulN(q, 1.0f / (2.0f + numFaces), ss); + + VertDataCopy(r, co0, ss); + VertDataAdd(r, co1, ss); + VertDataMulN(r, 0.5f, ss); + + VertDataCopy(co, q, ss); + VertDataSub(r, q, ss); + VertDataMulN(r, sharpness, ss); + VertDataAdd(co, r, ss); + } + } + } + + /* exterior vertex shift + * - old vertex points (shifting) + * - old exterior edge points + * - new interior face midpoints + */ + for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { + CCGVert *v = (CCGVert *) effectedV[ptrIdx]; + const float *co = VERT_getCo(v, curLvl); + float *nCo = VERT_getCo(v, nextLvl); + int sharpCount = 0, allSharp = 1; + float avgSharpness = 0.0; + int j, seam = VERT_seam(v), seamEdges = 0; + + for (j = 0; j < v->numEdges; j++) { + CCGEdge *e = v->edges[j]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam && _edge_isBoundary(e)) + seamEdges++; + + if (sharpness != 0.0f) { + sharpCount++; + avgSharpness += sharpness; + } + else { + allSharp = 0; + } + } + + if (sharpCount) { + avgSharpness /= sharpCount; + if (avgSharpness > 1.0f) { + avgSharpness = 1.0f; + } + } + + if (seamEdges < 2 || seamEdges != v->numEdges) + seam = 0; + + if (!v->numEdges || ss->meshIFC.simpleSubdiv) { + VertDataCopy(nCo, co, ss); + } + else if (_vert_isBoundary(v)) { + int numBoundary = 0; + + VertDataZero(r, ss); + for (j = 0; j < v->numEdges; j++) { + CCGEdge *e = v->edges[j]; + if (_edge_isBoundary(e)) { + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); + numBoundary++; + } + } + + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, 0.75f, ss); + VertDataMulN(r, 0.25f / numBoundary, ss); + VertDataAdd(nCo, r, ss); + } + else { + int cornerIdx = (1 + (1 << (curLvl))) - 2; + int numEdges = 0, numFaces = 0; + + VertDataZero(q, ss); + for (j = 0; j < v->numFaces; j++) { + CCGFace *f = v->faces[j]; + VertDataAdd(q, FACE_getIFCo(f, nextLvl, ccg_face_getVertIndex(f, v), cornerIdx, cornerIdx), ss); + numFaces++; + } + VertDataMulN(q, 1.0f / numFaces, ss); + VertDataZero(r, ss); + for (j = 0; j < v->numEdges; j++) { + CCGEdge *e = v->edges[j]; + VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); + numEdges++; + } + VertDataMulN(r, 1.0f / numEdges, ss); + + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, numEdges - 2.0f, ss); + VertDataAdd(nCo, q, ss); + VertDataAdd(nCo, r, ss); + VertDataMulN(nCo, 1.0f / numEdges, ss); + } + + if ((sharpCount > 1 && v->numFaces) || seam) { + VertDataZero(q, ss); + + if (seam) { + avgSharpness = 1.0f; + sharpCount = seamEdges; + allSharp = 1; + } + + for (j = 0; j < v->numEdges; j++) { + CCGEdge *e = v->edges[j]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam) { + if (_edge_isBoundary(e)) + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); + } + else if (sharpness != 0.0f) { + VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss); + } + } + + VertDataMulN(q, (float) 1 / sharpCount, ss); + + if (sharpCount != 2 || allSharp) { + /* q = q + (co - q) * avgSharpness */ + VertDataCopy(r, co, ss); + VertDataSub(r, q, ss); + VertDataMulN(r, avgSharpness, ss); + VertDataAdd(q, r, ss); + } + + /* r = co * 0.75 + q * 0.25 */ + VertDataCopy(r, co, ss); + VertDataMulN(r, 0.75f, ss); + VertDataMulN(q, 0.25f, ss); + VertDataAdd(r, q, ss); + + /* nCo = nCo + (r - nCo) * avgSharpness */ + VertDataSub(r, nCo, ss); + VertDataMulN(r, avgSharpness, ss); + VertDataAdd(nCo, r, ss); + } + } + + /* exterior edge interior shift + * - old exterior edge midpoints (shifting) + * - old exterior edge midpoints + * - new interior face midpoints + */ + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; + float sharpness = EDGE_getSharpness(e, curLvl); + int sharpCount = 0; + float avgSharpness = 0.0; + int x, j; + + if (sharpness != 0.0f) { + sharpCount = 2; + avgSharpness += sharpness; + + if (avgSharpness > 1.0f) { + avgSharpness = 1.0f; + } + } + else { + sharpCount = 0; + avgSharpness = 0; + } + + if (_edge_isBoundary(e)) { + for (x = 1; x < edgeSize - 1; x++) { + int fx = x * 2; + const float *co = EDGE_getCo(e, curLvl, x); + float *nCo = EDGE_getCo(e, nextLvl, fx); + + /* Average previous level's endpoints */ + VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss); + VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); + VertDataMulN(r, 0.5f, ss); + + /* nCo = nCo * 0.75 + r * 0.25 */ + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, 0.75f, ss); + VertDataMulN(r, 0.25f, ss); + VertDataAdd(nCo, r, ss); + } + } + else { + for (x = 1; x < edgeSize - 1; x++) { + int fx = x * 2; + const float *co = EDGE_getCo(e, curLvl, x); + float *nCo = EDGE_getCo(e, nextLvl, fx); + int numFaces = 0; + + VertDataZero(q, ss); + VertDataZero(r, ss); + VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss); + VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); + for (j = 0; j < e->numFaces; j++) { + CCGFace *f = e->faces[j]; + int f_ed_idx = ccg_face_getEdgeIndex(f, e); + VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize), ss); + VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize), ss); + + VertDataAdd(r, ccg_face_getIFCoEdge(f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize), ss); + numFaces++; + } + VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss); + VertDataMulN(r, 1.0f / (2.0f + numFaces), ss); + + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, (float) numFaces, ss); + VertDataAdd(nCo, q, ss); + VertDataAdd(nCo, r, ss); + VertDataMulN(nCo, 1.0f / (2 + numFaces), ss); + + if (sharpCount == 2) { + VertDataCopy(q, co, ss); + VertDataMulN(q, 6.0f, ss); + VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss); + VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss); + VertDataMulN(q, 1 / 8.0f, ss); + + VertDataSub(q, nCo, ss); + VertDataMulN(q, avgSharpness, ss); + VertDataAdd(nCo, q, ss); + } + } + } + } + +#pragma omp parallel private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + { + float *q, *r; + +#pragma omp critical + { + q = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q"); + r = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r"); + } + +#pragma omp for schedule(static) + for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { + CCGFace *f = (CCGFace *) effectedF[ptrIdx]; + int S, x, y; + + /* interior center point shift + * - old face center point (shifting) + * - old interior edge points + * - new interior face midpoints + */ + VertDataZero(q, ss); + for (S = 0; S < f->numVerts; S++) { + VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1), ss); + } + VertDataMulN(q, 1.0f / f->numVerts, ss); + VertDataZero(r, ss); + for (S = 0; S < f->numVerts; S++) { + VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1), ss); + } + VertDataMulN(r, 1.0f / f->numVerts, ss); + + VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss); + VertDataAdd((float *)FACE_getCenterData(f), q, ss); + VertDataAdd((float *)FACE_getCenterData(f), r, ss); + VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); + + for (S = 0; S < f->numVerts; S++) { + /* interior face shift + * - old interior face point (shifting) + * - new interior edge midpoints + * - new interior face midpoints + */ + for (x = 1; x < gridSize - 1; x++) { + for (y = 1; y < gridSize - 1; y++) { + int fx = x * 2; + int fy = y * 2; + const float *co = FACE_getIFCo(f, curLvl, S, x, y); + float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); + + VertDataAvg4(q, + FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1), + FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1), + ss); + + VertDataAvg4(r, + FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0), + FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0), + FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1), + FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1), + ss); + + VertDataCopy(nCo, co, ss); + VertDataSub(nCo, q, ss); + VertDataMulN(nCo, 0.25f, ss); + VertDataAdd(nCo, r, ss); + } + } + + /* interior edge interior shift + * - old interior edge point (shifting) + * - new interior edge midpoints + * - new interior face midpoints + */ + for (x = 1; x < gridSize - 1; x++) { + int fx = x * 2; + const float *co = FACE_getIECo(f, curLvl, S, x); + float *nCo = FACE_getIECo(f, nextLvl, S, fx); + + VertDataAvg4(q, + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1), + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1), + FACE_getIFCo(f, nextLvl, S, fx + 1, +1), + FACE_getIFCo(f, nextLvl, S, fx - 1, +1), ss); + + VertDataAvg4(r, + FACE_getIECo(f, nextLvl, S, fx - 1), + FACE_getIECo(f, nextLvl, S, fx + 1), + FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx), + FACE_getIFCo(f, nextLvl, S, fx, 1), + ss); + + VertDataCopy(nCo, co, ss); + VertDataSub(nCo, q, ss); + VertDataMulN(nCo, 0.25f, ss); + VertDataAdd(nCo, r, ss); + } + } + } + +#pragma omp critical + { + MEM_freeN(q); + MEM_freeN(r); + } + } + + /* copy down */ + edgeSize = ccg_edgesize(nextLvl); + gridSize = ccg_gridsize(nextLvl); + cornerIdx = gridSize - 1; + +#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + for (i = 0; i < numEffectedE; i++) { + CCGEdge *e = effectedE[i]; + VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); + VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss); + } + +#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT) + for (i = 0; i < numEffectedF; i++) { + CCGFace *f = effectedF[i]; + int S, x; + + for (S = 0; S < f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss); + for (x = 1; x < gridSize - 1; x++) { + float *co = FACE_getIECo(f, nextLvl, S, x); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss); + } + for (x = 0; x < gridSize - 1; x++) { + int eI = gridSize - 1 - x; + VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss); + } + } + } +} + +void ccgSubSurf__sync_legacy(CCGSubSurf *ss) +{ + CCGVert **effectedV; + CCGEdge **effectedE; + CCGFace **effectedF; + int numEffectedV, numEffectedE, numEffectedF; + int subdivLevels = ss->subdivLevels; + int vertDataSize = ss->meshIFC.vertDataSize; + int i, j, ptrIdx, S; + int curLvl, nextLvl; + void *q = ss->q, *r = ss->r; + + effectedV = MEM_mallocN(sizeof(*effectedV) * ss->vMap->numEntries, "CCGSubsurf effectedV"); + effectedE = MEM_mallocN(sizeof(*effectedE) * ss->eMap->numEntries, "CCGSubsurf effectedE"); + effectedF = MEM_mallocN(sizeof(*effectedF) * ss->fMap->numEntries, "CCGSubsurf effectedF"); + numEffectedV = numEffectedE = numEffectedF = 0; + for (i = 0; i < ss->vMap->curSize; i++) { + CCGVert *v = (CCGVert *) ss->vMap->buckets[i]; + for (; v; v = v->next) { + if (v->flags & Vert_eEffected) { + effectedV[numEffectedV++] = v; + + for (j = 0; j < v->numEdges; j++) { + CCGEdge *e = v->edges[j]; + if (!(e->flags & Edge_eEffected)) { + effectedE[numEffectedE++] = e; + e->flags |= Edge_eEffected; + } + } + + for (j = 0; j < v->numFaces; j++) { + CCGFace *f = v->faces[j]; + if (!(f->flags & Face_eEffected)) { + effectedF[numEffectedF++] = f; + f->flags |= Face_eEffected; + } + } + } + } + } + + curLvl = 0; + nextLvl = curLvl + 1; + + for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { + CCGFace *f = effectedF[ptrIdx]; + void *co = FACE_getCenterData(f); + VertDataZero(co, ss); + for (i = 0; i < f->numVerts; i++) { + VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), ss); + } + VertDataMulN(co, 1.0f / f->numVerts, ss); + + f->flags = 0; + } + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = effectedE[ptrIdx]; + void *co = EDGE_getCo(e, nextLvl, 1); + float sharpness = EDGE_getSharpness(e, curLvl); + + if (_edge_isBoundary(e) || sharpness >= 1.0f) { + VertDataCopy(co, VERT_getCo(e->v0, curLvl), ss); + VertDataAdd(co, VERT_getCo(e->v1, curLvl), ss); + VertDataMulN(co, 0.5f, ss); + } + else { + int numFaces = 0; + VertDataCopy(q, VERT_getCo(e->v0, curLvl), ss); + VertDataAdd(q, VERT_getCo(e->v1, curLvl), ss); + for (i = 0; i < e->numFaces; i++) { + CCGFace *f = e->faces[i]; + VertDataAdd(q, (float *)FACE_getCenterData(f), ss); + numFaces++; + } + VertDataMulN(q, 1.0f / (2.0f + numFaces), ss); + + VertDataCopy(r, VERT_getCo(e->v0, curLvl), ss); + VertDataAdd(r, VERT_getCo(e->v1, curLvl), ss); + VertDataMulN(r, 0.5f, ss); + + VertDataCopy(co, q, ss); + VertDataSub(r, q, ss); + VertDataMulN(r, sharpness, ss); + VertDataAdd(co, r, ss); + } + + /* edge flags cleared later */ + } + for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { + CCGVert *v = effectedV[ptrIdx]; + void *co = VERT_getCo(v, curLvl); + void *nCo = VERT_getCo(v, nextLvl); + int sharpCount = 0, allSharp = 1; + float avgSharpness = 0.0; + int seam = VERT_seam(v), seamEdges = 0; + + for (i = 0; i < v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam && _edge_isBoundary(e)) + seamEdges++; + + if (sharpness != 0.0f) { + sharpCount++; + avgSharpness += sharpness; + } + else { + allSharp = 0; + } + } + + if (sharpCount) { + avgSharpness /= sharpCount; + if (avgSharpness > 1.0f) { + avgSharpness = 1.0f; + } + } + + if (seamEdges < 2 || seamEdges != v->numEdges) + seam = 0; + + if (!v->numEdges || ss->meshIFC.simpleSubdiv) { + VertDataCopy(nCo, co, ss); + } + else if (_vert_isBoundary(v)) { + int numBoundary = 0; + + VertDataZero(r, ss); + for (i = 0; i < v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + if (_edge_isBoundary(e)) { + VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); + numBoundary++; + } + } + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, 0.75f, ss); + VertDataMulN(r, 0.25f / numBoundary, ss); + VertDataAdd(nCo, r, ss); + } + else { + int numEdges = 0, numFaces = 0; + + VertDataZero(q, ss); + for (i = 0; i < v->numFaces; i++) { + CCGFace *f = v->faces[i]; + VertDataAdd(q, (float *)FACE_getCenterData(f), ss); + numFaces++; + } + VertDataMulN(q, 1.0f / numFaces, ss); + VertDataZero(r, ss); + for (i = 0; i < v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); + numEdges++; + } + VertDataMulN(r, 1.0f / numEdges, ss); + + VertDataCopy(nCo, co, ss); + VertDataMulN(nCo, numEdges - 2.0f, ss); + VertDataAdd(nCo, q, ss); + VertDataAdd(nCo, r, ss); + VertDataMulN(nCo, 1.0f / numEdges, ss); + } + + if (sharpCount > 1 || seam) { + VertDataZero(q, ss); + + if (seam) { + avgSharpness = 1.0f; + sharpCount = seamEdges; + allSharp = 1; + } + + for (i = 0; i < v->numEdges; i++) { + CCGEdge *e = v->edges[i]; + float sharpness = EDGE_getSharpness(e, curLvl); + + if (seam) { + if (_edge_isBoundary(e)) { + CCGVert *oV = _edge_getOtherVert(e, v); + VertDataAdd(q, VERT_getCo(oV, curLvl), ss); + } + } + else if (sharpness != 0.0f) { + CCGVert *oV = _edge_getOtherVert(e, v); + VertDataAdd(q, VERT_getCo(oV, curLvl), ss); + } + } + + VertDataMulN(q, (float) 1 / sharpCount, ss); + + if (sharpCount != 2 || allSharp) { + /* q = q + (co - q) * avgSharpness */ + VertDataCopy(r, co, ss); + VertDataSub(r, q, ss); + VertDataMulN(r, avgSharpness, ss); + VertDataAdd(q, r, ss); + } + + /* r = co * 0.75 + q * 0.25 */ + VertDataCopy(r, co, ss); + VertDataMulN(r, 0.75f, ss); + VertDataMulN(q, 0.25f, ss); + VertDataAdd(r, q, ss); + + /* nCo = nCo + (r - nCo) * avgSharpness */ + VertDataSub(r, nCo, ss); + VertDataMulN(r, avgSharpness, ss); + VertDataAdd(nCo, r, ss); + } + + /* vert flags cleared later */ + } + + if (ss->useAgeCounts) { + for (i = 0; i < numEffectedV; i++) { + CCGVert *v = effectedV[i]; + byte *userData = ccgSubSurf_getVertUserData(ss, v); + *((int *) &userData[ss->vertUserAgeOffset]) = ss->currentAge; + } + + for (i = 0; i < numEffectedE; i++) { + CCGEdge *e = effectedE[i]; + byte *userData = ccgSubSurf_getEdgeUserData(ss, e); + *((int *) &userData[ss->edgeUserAgeOffset]) = ss->currentAge; + } + + for (i = 0; i < numEffectedF; i++) { + CCGFace *f = effectedF[i]; + byte *userData = ccgSubSurf_getFaceUserData(ss, f); + *((int *) &userData[ss->faceUserAgeOffset]) = ss->currentAge; + } + } + + for (i = 0; i < numEffectedE; i++) { + CCGEdge *e = effectedE[i]; + VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); + VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss); + } + for (i = 0; i < numEffectedF; i++) { + CCGFace *f = effectedF[i]; + for (S = 0; S < f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); + VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss); + + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss); + VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss); + } + } + + for (curLvl = 1; curLvl < subdivLevels; curLvl++) + ccgSubSurf__calcSubdivLevel(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF, curLvl); + + if (ss->calcVertNormals) + ccgSubSurf__calcVertNormals(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF); + + for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { + CCGVert *v = effectedV[ptrIdx]; + v->flags = 0; + } + for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { + CCGEdge *e = effectedE[ptrIdx]; + e->flags = 0; + } + + MEM_freeN(effectedF); + MEM_freeN(effectedE); + MEM_freeN(effectedV); + +#ifdef DUMP_RESULT_GRIDS + ccgSubSurf__dumpCoords(ss); +#endif +} + +/* ** Public API exposed to other areas which depends on old CCG code. ** */ + +/* Update normals for specified faces. */ +CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) +{ + CCGVert **effectedV; + CCGEdge **effectedE; + int i, numEffectedV, numEffectedE, freeF; + + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); + ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, + &effectedV, &numEffectedV, &effectedE, &numEffectedE); + + if (ss->calcVertNormals) + ccgSubSurf__calcVertNormals(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF); + + for (i = 0; i < numEffectedV; i++) + effectedV[i]->flags = 0; + for (i = 0; i < numEffectedE; i++) + effectedE[i]->flags = 0; + for (i = 0; i < numEffectedF; i++) + effectedF[i]->flags = 0; + + MEM_freeN(effectedE); + MEM_freeN(effectedV); + if (freeF) MEM_freeN(effectedF); + + return eCCGError_None; +} + +/* compute subdivision levels from a given starting point, used by + * multires subdivide/propagate, by filling in coordinates at a + * certain level, and then subdividing that up to the highest level */ +CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) +{ + CCGVert **effectedV; + CCGEdge **effectedE; + int numEffectedV, numEffectedE, freeF, i; + int curLvl, subdivLevels = ss->subdivLevels; + + ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); + ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF, + &effectedV, &numEffectedV, &effectedE, &numEffectedE); + + for (curLvl = lvl; curLvl < subdivLevels; curLvl++) { + ccgSubSurf__calcSubdivLevel(ss, + effectedV, effectedE, effectedF, + numEffectedV, numEffectedE, numEffectedF, curLvl); + } + + for (i = 0; i < numEffectedV; i++) + effectedV[i]->flags = 0; + for (i = 0; i < numEffectedE; i++) + effectedE[i]->flags = 0; + for (i = 0; i < numEffectedF; i++) + effectedF[i]->flags = 0; + + MEM_freeN(effectedE); + MEM_freeN(effectedV); + if (freeF) MEM_freeN(effectedF); + + return eCCGError_None; +} diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c new file mode 100644 index 00000000000..9af69115559 --- /dev/null +++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c @@ -0,0 +1,306 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/CCGSubSurf_util.c + * \ingroup bke + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" +#include "BLI_sys_types.h" // for intptr_t support + +#include "BLI_utildefines.h" /* for BLI_assert */ + +#include "CCGSubSurf.h" +#include "CCGSubSurf_intern.h" + +/** + * Hash implementation. + */ + +static int kHashSizes[] = { + 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, + 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 +}; + +/* Generic hash functions. */ + +EHash *ccg_ehash_new(int estimatedNumEntries, + CCGAllocatorIFC *allocatorIFC, + CCGAllocatorHDL allocator) +{ + EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh)); + eh->allocatorIFC = *allocatorIFC; + eh->allocator = allocator; + eh->numEntries = 0; + eh->curSizeIdx = 0; + while (kHashSizes[eh->curSizeIdx] < estimatedNumEntries) + eh->curSizeIdx++; + eh->curSize = kHashSizes[eh->curSizeIdx]; + eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); + + return eh; +} + +void ccg_ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) +{ + int numBuckets = eh->curSize; + + while (numBuckets--) { + EHEntry *entry = eh->buckets[numBuckets]; + + while (entry) { + EHEntry *next = entry->next; + + freeEntry(entry, userData); + + entry = next; + } + } + + EHASH_free(eh, eh->buckets); + EHASH_free(eh, eh); +} + +void ccg_ehash_insert(EHash *eh, EHEntry *entry) +{ + int numBuckets = eh->curSize; + int hash = EHASH_hash(eh, entry->key); + entry->next = eh->buckets[hash]; + eh->buckets[hash] = entry; + eh->numEntries++; + + if (UNLIKELY(eh->numEntries > (numBuckets * 3))) { + EHEntry **oldBuckets = eh->buckets; + eh->curSize = kHashSizes[++eh->curSizeIdx]; + + eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); + memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); + + while (numBuckets--) { + for (entry = oldBuckets[numBuckets]; entry; ) { + EHEntry *next = entry->next; + + hash = EHASH_hash(eh, entry->key); + entry->next = eh->buckets[hash]; + eh->buckets[hash] = entry; + + entry = next; + } + } + + EHASH_free(eh, oldBuckets); + } +} + +void *ccg_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) +{ + int hash = EHASH_hash(eh, key); + void **prevp = (void **) &eh->buckets[hash]; + EHEntry *entry; + + for (; (entry = *prevp); prevp = (void **) &entry->next) { + if (entry->key == key) { + *prevp_r = (void **) prevp; + return entry; + } + } + + return NULL; +} + +void *ccg_ehash_lookup(EHash *eh, void *key) +{ + int hash = EHASH_hash(eh, key); + EHEntry *entry; + + for (entry = eh->buckets[hash]; entry; entry = entry->next) { + if (entry->key == key) + break; + } + + return entry; +} + +/* Hash elements iteration. */ + +void ccg_ehashIterator_init(EHash *eh, EHashIterator *ehi) +{ + /* fill all members */ + ehi->eh = eh; + ehi->curBucket = -1; + ehi->curEntry = NULL; + + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket == ehi->eh->curSize) + break; + ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; + } +} + +void *ccg_ehashIterator_getCurrent(EHashIterator *ehi) +{ + return ehi->curEntry; +} + +void ccg_ehashIterator_next(EHashIterator *ehi) +{ + if (ehi->curEntry) { + ehi->curEntry = ehi->curEntry->next; + while (!ehi->curEntry) { + ehi->curBucket++; + if (ehi->curBucket == ehi->eh->curSize) + break; + ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; + } + } +} +int ccg_ehashIterator_isStopped(EHashIterator *ehi) +{ + return !ehi->curEntry; +} + +/** + * Standard allocator implementarion. + */ + +static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) +{ + return MEM_mallocN(numBytes, "CCG standard alloc"); +} + +static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a), + void *ptr, + int newSize, + int UNUSED(oldSize)) +{ + return MEM_reallocN(ptr, newSize); +} + +static void _stdAllocator_free(CCGAllocatorHDL UNUSED(a), void *ptr) +{ + MEM_freeN(ptr); +} + +CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void) +{ + static CCGAllocatorIFC ifc; + + ifc.alloc = _stdAllocator_alloc; + ifc.realloc = _stdAllocator_realloc; + ifc.free = _stdAllocator_free; + ifc.release = NULL; + + return &ifc; +} + +/** + * Catmull-Clark Gridding Subdivision Surface. + */ + +#ifdef DUMP_RESULT_GRIDS +void ccgSubSurf__dumpCoords(CCGSubSurf *ss) +{ + int vertDataSize = ss->meshIFC.vertDataSize; + int subdivLevels = ss->subdivLevels; + int gridSize = ccg_gridsize(subdivLevels); + int edgeSize = ccg_edgesize(subdivLevels); + int i, index, S; + + for (i = 0, index = 0; i < ss->vMap->curSize; i++) { + CCGVert *v = (CCGVert *) ss->vMap->buckets[i]; + for (; v; v = v->next, index++) { + float *co = VERT_getCo(v, subdivLevels); + printf("vertex index=%d, co=(%f, %f, %f)\n", + index, co[0], co[1], co[2]); + } + } + + for (i = 0, index = 0; i < ss->eMap->curSize; i++) { + CCGEdge *e = (CCGEdge *) ss->eMap->buckets[i]; + for (; e; e = e->next, index++) { + int x; + float *co = VERT_getCo(e->v0, subdivLevels); + printf("edge index=%d, start_co=(%f, %f, %f)\n", + index, co[0], co[1], co[2]); + for (x = 0; x < edgeSize; x++) { + float *co = EDGE_getCo(e, subdivLevels, x); + printf("edge index=%d, seg=%d, co=(%f, %f, %f)\n", + index, x, co[0], co[1], co[2]); + } + co = VERT_getCo(e->v1, subdivLevels); + printf("edge index=%d, end_co=(%f, %f, %f)\n", + index, co[0], co[1], co[2]); + } + } + + for (i = 0, index = 0; i < ss->fMap->curSize; i++) { + CCGFace *f = (CCGFace *) ss->fMap->buckets[i]; + for (; f; f = f->next, index++) { + for (S = 0; S < f->numVerts; S++) { + CCGVert *v = FACE_getVerts(f)[S]; + float *co = VERT_getCo(v, subdivLevels); + printf("face index=%d, vertex=%d, coord=(%f, %f, %f)\n", + index, S, co[0], co[1], co[2]); + } + } + } + + for (i = 0, index = 0; i < ss->fMap->curSize; i++) { + CCGFace *f = (CCGFace *) ss->fMap->buckets[i]; + for (; f; f = f->next, index++) { + for (S = 0; S < f->numVerts; S++) { + CCGEdge *e = FACE_getEdges(f)[S]; + float *co1 = VERT_getCo(e->v0, subdivLevels); + float *co2 = VERT_getCo(e->v1, subdivLevels); + printf("face index=%d, edge=%d, coord1=(%f, %f, %f), coord2=(%f, %f, %f)\n", + index, S, co1[0], co1[1], co1[2], co2[0], co2[1], co2[2]); + } + } + } + + for (i = 0, index = 0; i < ss->fMap->curSize; i++) { + CCGFace *f = (CCGFace *) ss->fMap->buckets[i]; + for (; f; f = f->next, index++) { + for (S = 0; S < f->numVerts; S++) { + int x, y; + for (x = 0; x < gridSize; x++) { + for (y = 0; y < gridSize; y++) { + float *co = FACE_getIFCo(f, subdivLevels, S, x, y); + printf("face index=%d. corner=%d, x=%d, y=%d, coord=(%f, %f, %f)\n", + index, S, x, y, co[0], co[1], co[2]); + } + } + for (x = 0; x < gridSize; x++) { + float *co = FACE_getIECo(f, subdivLevels, S, x); + printf("face index=%d. cornder=%d, ie_index=%d, coord=(%f, %f, %f)\n", + index, S, x, co[0], co[1], co[2]); + } + } + } + } +} +#endif /* DUMP_RESULT_GRIDS */ |