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.
This commit is contained in:
Sergey Sharybin
2015-07-20 15:05:16 +02:00
parent 6190d75b5a
commit ccc3c2dbda
6 changed files with 2119 additions and 1744 deletions

View File

@@ -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
)

View File

@@ -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 ***/

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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;
}

View File

@@ -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 */