2011-10-10 09:38:02 +00:00
|
|
|
|
2011-02-27 20:40:57 +00:00
|
|
|
/** \file blender/blenkernel/intern/CCGSubSurf.c
|
|
|
|
* \ingroup bke
|
|
|
|
*/
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2005-03-22 06:11:25 +00:00
|
|
|
#include <math.h>
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
#include "CCGSubSurf.h"
|
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2008-08-17 17:08:00 +00:00
|
|
|
#include "BLO_sys_types.h" // for intptr_t support
|
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define CCG_INLINE __inline
|
|
|
|
#else
|
|
|
|
#define CCG_INLINE inline
|
|
|
|
#endif
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
/* copied from BKE_utildefines.h ugh */
|
|
|
|
#ifdef __GNUC__
|
|
|
|
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
|
|
|
#else
|
|
|
|
# define UNUSED(x) x
|
|
|
|
#endif
|
|
|
|
|
2009-11-12 15:05:51 +00:00
|
|
|
/* used for normalize_v3 in BLI_math_vector
|
|
|
|
* float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */
|
|
|
|
#define EPSILON (1.0e-35f)
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/***/
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
2008-08-17 17:08:00 +00:00
|
|
|
#define EHASH_hash(eh, item) (((uintptr_t) (item))%((unsigned int) (eh)->curSize))
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
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 (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);
|
2005-03-31 16:08:29 +00:00
|
|
|
void **prevp = (void**) &eh->buckets[hash];
|
2005-03-27 14:37:00 +00:00
|
|
|
EHEntry *entry;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2005-03-31 16:08:29 +00:00
|
|
|
for (; (entry = *prevp); prevp = (void**) &entry->next) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (entry->key==key) {
|
2005-03-27 14:37:00 +00:00
|
|
|
*prevp_r = (void**) prevp;
|
2005-03-21 01:34:27 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
typedef struct _EHashIterator {
|
|
|
|
EHash *eh;
|
|
|
|
int curBucket;
|
|
|
|
EHEntry *curEntry;
|
|
|
|
} EHashIterator;
|
|
|
|
|
|
|
|
static EHashIterator *_ehashIterator_new(EHash *eh) {
|
|
|
|
EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi));
|
|
|
|
ehi->eh = eh;
|
|
|
|
ehi->curEntry = NULL;
|
|
|
|
ehi->curBucket = -1;
|
|
|
|
while (!ehi->curEntry) {
|
|
|
|
ehi->curBucket++;
|
|
|
|
if (ehi->curBucket==ehi->eh->curSize)
|
|
|
|
break;
|
|
|
|
ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
|
|
|
|
}
|
|
|
|
return ehi;
|
|
|
|
}
|
|
|
|
static void _ehashIterator_free(EHashIterator *ehi) {
|
|
|
|
EHASH_free(ehi->eh, ehi);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *_ehashIterator_getCurrent(EHashIterator *ehi) {
|
|
|
|
return ehi->curEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _ehashIterator_next(EHashIterator *ehi) {
|
|
|
|
if (ehi->curEntry) {
|
2010-03-22 09:30:00 +00:00
|
|
|
ehi->curEntry = ehi->curEntry->next;
|
2005-03-21 01:34:27 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return malloc(numBytes);
|
|
|
|
}
|
2010-10-17 06:38:56 +00:00
|
|
|
static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a), void *ptr, int newSize, int UNUSED(oldSize)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return realloc(ptr, newSize);
|
|
|
|
}
|
2010-10-17 06:38:56 +00:00
|
|
|
static void _stdAllocator_free(CCGAllocatorHDL UNUSED(a), void *ptr) {
|
2005-03-21 01:34:27 +00:00
|
|
|
free(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
static int VertDataEqual(float *a, float *b) {
|
|
|
|
return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
#define VertDataZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
|
|
|
|
#define VertDataCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
|
|
|
|
#define VertDataAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
|
|
|
|
#define VertDataSub(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]-=_b[0]; _a[1]-=_b[1]; _a[2]-=_b[2]; }
|
|
|
|
#define VertDataMulN(av, n) { float *_a = (float*) av; _a[0]*=n; _a[1]*=n; _a[2]*=n; }
|
2005-04-04 05:21:20 +00:00
|
|
|
#define VertDataAvg4(tv, av, bv, cv, dv) \
|
|
|
|
{ \
|
2008-09-29 17:08:11 +00:00
|
|
|
float *_t = (float*) tv, *_a = (float*) av, *_b = (float*) bv, *_c = (float*) cv, *_d = (float*) dv; \
|
2011-03-27 17:22:04 +00:00
|
|
|
_t[0] = (_a[0]+_b[0]+_c[0]+_d[0])*.25f; \
|
|
|
|
_t[1] = (_a[1]+_b[1]+_c[1]+_d[1])*.25f; \
|
|
|
|
_t[2] = (_a[2]+_b[2]+_c[2]+_d[2])*.25f; \
|
2005-04-04 05:21:20 +00:00
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
#define NormZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
|
|
|
|
#define NormCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
|
|
|
|
#define NormAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
|
2005-06-23 23:44:22 +00:00
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
static int _edge_isBoundary(CCGEdge *e);
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2011-02-17 12:05:09 +00:00
|
|
|
enum {
|
2005-03-21 01:34:27 +00:00
|
|
|
Vert_eEffected= (1<<0),
|
|
|
|
Vert_eChanged= (1<<1),
|
2006-01-10 11:36:57 +00:00
|
|
|
Vert_eSeam= (1<<2),
|
2011-02-17 12:05:09 +00:00
|
|
|
} /*VertFlags*/;
|
|
|
|
enum {
|
2005-03-21 01:34:27 +00:00
|
|
|
Edge_eEffected= (1<<0),
|
2011-02-17 12:05:09 +00:00
|
|
|
} /*CCGEdgeFlags*/;
|
|
|
|
enum {
|
2005-03-21 01:34:27 +00:00
|
|
|
Face_eEffected= (1<<0),
|
2011-02-17 12:05:09 +00:00
|
|
|
} /*FaceFlags*/;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
struct _CCGVert {
|
|
|
|
CCGVert *next; /* EHData.next */
|
|
|
|
CCGVertHDL vHDL; /* EHData.key */
|
|
|
|
|
|
|
|
short numEdges, numFaces, flags, pad;
|
|
|
|
|
|
|
|
CCGEdge **edges;
|
|
|
|
CCGFace **faces;
|
|
|
|
// byte *levelData;
|
|
|
|
// byte *userData;
|
|
|
|
};
|
|
|
|
#define VERT_getLevelData(v) ((byte*) &(v)[1])
|
|
|
|
|
|
|
|
struct _CCGEdge {
|
|
|
|
CCGEdge *next; /* EHData.next */
|
|
|
|
CCGEdgeHDL eHDL; /* EHData.key */
|
|
|
|
|
|
|
|
short numFaces, flags;
|
2005-04-01 02:07:34 +00:00
|
|
|
float crease;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
CCGVert *v0,*v1;
|
|
|
|
CCGFace **faces;
|
|
|
|
|
|
|
|
// byte *levelData;
|
|
|
|
// byte *userData;
|
|
|
|
};
|
|
|
|
#define EDGE_getLevelData(e) ((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;
|
|
|
|
};
|
|
|
|
#define FACE_getVerts(f) ((CCGVert**) &(f)[1])
|
|
|
|
#define FACE_getEdges(f) ((CCGEdge**) &(FACE_getVerts(f)[(f)->numVerts]))
|
|
|
|
#define FACE_getCenterData(f) ((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;
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGAllocatorIFC allocatorIFC;
|
|
|
|
CCGAllocatorHDL allocator;
|
|
|
|
|
|
|
|
int subdivLevels;
|
|
|
|
int numGrids;
|
|
|
|
int allowEdgeCreation;
|
2005-04-04 02:55:56 +00:00
|
|
|
float defaultCreaseValue;
|
2005-08-20 09:16:09 +00:00
|
|
|
void *defaultEdgeUserData;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
void *q, *r;
|
2005-04-03 21:52:10 +00:00
|
|
|
|
|
|
|
// data for calc vert normals
|
|
|
|
int calcVertNormals;
|
|
|
|
int normalDataOffset;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
// 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))
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGVert *v = CCGSUBSURF_alloc(ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * (ss->subdivLevels+1) + ss->meshIFC.vertUserSize);
|
|
|
|
byte *userData;
|
|
|
|
|
|
|
|
v->vHDL = vHDL;
|
|
|
|
v->edges = NULL;
|
|
|
|
v->faces = NULL;
|
|
|
|
v->numEdges = v->numFaces = 0;
|
|
|
|
v->flags = 0;
|
|
|
|
|
|
|
|
userData = ccgSubSurf_getVertUserData(ss, v);
|
|
|
|
memset(userData, 0, ss->meshIFC.vertUserSize);
|
|
|
|
if (ss->useAgeCounts) *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
static void _vert_remEdge(CCGVert *v, CCGEdge *e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int i;
|
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
if (v->edges[i]==e) {
|
|
|
|
v->edges[i] = v->edges[--v->numEdges];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
static void _vert_remFace(CCGVert *v, CCGFace *f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int i;
|
|
|
|
for (i=0; i<v->numFaces; i++) {
|
|
|
|
if (v->faces[i]==f) {
|
|
|
|
v->faces[i] = v->faces[--v->numFaces];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
|
|
|
|
v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges+1)*sizeof(*v->edges), v->numEdges*sizeof(*v->edges));
|
|
|
|
v->edges[v->numEdges++] = e;
|
|
|
|
}
|
|
|
|
static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
|
|
|
|
v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces+1)*sizeof(*v->faces), v->numFaces*sizeof(*v->faces));
|
|
|
|
v->faces[v->numFaces++] = f;
|
|
|
|
}
|
|
|
|
static CCGEdge *_vert_findEdgeTo(CCGVert *v, CCGVert *vQ) {
|
|
|
|
int i;
|
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[v->numEdges-1-i]; // XXX, note reverse
|
|
|
|
if ( (e->v0==v && e->v1==vQ) ||
|
|
|
|
(e->v1==v && e->v0==vQ))
|
|
|
|
return e;
|
|
|
|
}
|
2011-02-13 10:52:18 +00:00
|
|
|
return NULL;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
static int _vert_isBoundary(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];
|
|
|
|
}
|
2005-08-03 04:04:05 +00:00
|
|
|
static float *_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) {
|
|
|
|
return (float*) &VERT_getLevelData(v)[lvl*dataSize + normalDataOffset];
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
static void _vert_free(CCGVert *v, CCGSubSurf *ss) {
|
|
|
|
CCGSUBSURF_free(ss, v->edges);
|
|
|
|
CCGSUBSURF_free(ss, v->faces);
|
|
|
|
CCGSUBSURF_free(ss, v);
|
|
|
|
}
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
static int VERT_seam(CCGVert *v) {
|
2006-01-10 11:36:57 +00:00
|
|
|
return ((v->flags & Vert_eSeam) != 0);
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/***/
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGEdge *e = CCGSUBSURF_alloc(ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1) + ss->meshIFC.edgeUserSize);
|
|
|
|
byte *userData;
|
|
|
|
|
|
|
|
e->eHDL = eHDL;
|
|
|
|
e->v0 = v0;
|
|
|
|
e->v1 = v1;
|
2005-04-01 02:07:34 +00:00
|
|
|
e->crease = crease;
|
2005-03-21 01:34:27 +00:00
|
|
|
e->faces = NULL;
|
|
|
|
e->numFaces = 0;
|
|
|
|
e->flags = 0;
|
|
|
|
_vert_addEdge(v0, e, ss);
|
|
|
|
_vert_addEdge(v1, e, ss);
|
|
|
|
|
|
|
|
userData = ccgSubSurf_getEdgeUserData(ss, e);
|
|
|
|
memset(userData, 0, ss->meshIFC.edgeUserSize);
|
|
|
|
if (ss->useAgeCounts) *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
static void _edge_remFace(CCGEdge *e, CCGFace *f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int i;
|
|
|
|
for (i=0; i<e->numFaces; i++) {
|
|
|
|
if (e->faces[i]==f) {
|
|
|
|
e->faces[i] = e->faces[--e->numFaces];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-27 14:17:28 +00:00
|
|
|
static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
|
2005-03-21 01:34:27 +00:00
|
|
|
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(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 = lvl + (1<<lvl) - 1;
|
|
|
|
return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
|
|
|
|
}
|
2005-04-03 21:52:10 +00:00
|
|
|
static float *_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset) {
|
|
|
|
int levelBase = lvl + (1<<lvl) - 1;
|
|
|
|
return (float*) &EDGE_getLevelData(e)[dataSize*(levelBase + x) + normalDataOffset];
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) {
|
|
|
|
int levelBase = lvl + (1<<lvl) - 1;
|
|
|
|
if (v==e->v0) {
|
|
|
|
return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
|
|
|
|
} else {
|
|
|
|
return &EDGE_getLevelData(e)[dataSize*(levelBase + (1<<lvl) - x)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _edge_free(CCGEdge *e, CCGSubSurf *ss) {
|
|
|
|
CCGSUBSURF_free(ss, e->faces);
|
|
|
|
CCGSUBSURF_free(ss, e);
|
|
|
|
}
|
|
|
|
static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) {
|
2008-09-29 17:08:11 +00:00
|
|
|
_vert_remEdge(e->v0, e);
|
|
|
|
_vert_remEdge(e->v1, e);
|
2005-03-21 01:34:27 +00:00
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
|
|
|
_edge_free(e, ss);
|
|
|
|
}
|
|
|
|
|
2007-06-09 10:51:02 +00:00
|
|
|
static float EDGE_getSharpness(CCGEdge *e, int lvl) {
|
|
|
|
if (!lvl)
|
|
|
|
return e->crease;
|
|
|
|
else if (!e->crease)
|
2011-03-27 17:22:04 +00:00
|
|
|
return 0.0f;
|
|
|
|
else if (e->crease - lvl < 0.0f)
|
|
|
|
return 0.0f;
|
2007-06-09 10:51:02 +00:00
|
|
|
else
|
|
|
|
return e->crease - lvl;
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
|
|
|
|
CCGFace *f = CCGSUBSURF_alloc(ss, sizeof(CCGFace) + sizeof(CCGVert*)*numVerts + sizeof(CCGEdge*)*numVerts + ss->meshIFC.vertDataSize *(1 + numVerts*maxGridSize + numVerts*maxGridSize*maxGridSize) + ss->meshIFC.faceUserSize);
|
|
|
|
byte *userData;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
f->numVerts = numVerts;
|
|
|
|
f->fHDL = fHDL;
|
|
|
|
f->flags = 0;
|
|
|
|
|
|
|
|
for (i=0; i<numVerts; i++) {
|
|
|
|
FACE_getVerts(f)[i] = verts[i];
|
|
|
|
FACE_getEdges(f)[i] = edges[i];
|
|
|
|
_vert_addFace(verts[i], f, ss);
|
|
|
|
_edge_addFace(edges[i], f, ss);
|
|
|
|
}
|
|
|
|
|
|
|
|
userData = ccgSubSurf_getFaceUserData(ss, f);
|
|
|
|
memset(userData, 0, ss->meshIFC.faceUserSize);
|
|
|
|
if (ss->useAgeCounts) *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
static CCG_INLINE void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int maxGridSize = 1 + (1<<(levels-1));
|
|
|
|
int spacing = 1<<(levels-lvl);
|
|
|
|
byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
|
|
|
|
return &gridBase[dataSize*x*spacing];
|
|
|
|
}
|
2010-01-30 09:32:05 +00:00
|
|
|
static CCG_INLINE void *_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) {
|
|
|
|
int maxGridSize = 1 + (1<<(levels-1));
|
|
|
|
int spacing = 1<<(levels-lvl);
|
|
|
|
byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
|
|
|
|
return &gridBase[dataSize*x*spacing + normalDataOffset];
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
static CCG_INLINE void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int maxGridSize = 1 + (1<<(levels-1));
|
|
|
|
int spacing = 1<<(levels-lvl);
|
|
|
|
byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
|
|
|
|
return &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing)];
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
static CCG_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) {
|
2005-04-03 21:52:10 +00:00
|
|
|
int maxGridSize = 1 + (1<<(levels-1));
|
|
|
|
int spacing = 1<<(levels-lvl);
|
|
|
|
byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
|
|
|
|
return (float*) &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing) + normalDataOffset];
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
static 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;
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
static CCG_INLINE void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int maxGridSize = 1 + (1<<(levels-1));
|
|
|
|
int spacing = 1<<(levels-lvl);
|
|
|
|
int S, x, y, cx, cy;
|
|
|
|
|
|
|
|
for (S=0; S<f->numVerts; S++)
|
|
|
|
if (FACE_getEdges(f)[S]==e)
|
|
|
|
break;
|
|
|
|
|
|
|
|
eX = eX*spacing;
|
|
|
|
eY = eY*spacing;
|
|
|
|
if (e->v0!=FACE_getVerts(f)[S]) {
|
|
|
|
eX = (maxGridSize*2 - 1)-1 - eX;
|
|
|
|
}
|
|
|
|
y = maxGridSize - 1 - eX;
|
|
|
|
x = maxGridSize - 1 - eY;
|
|
|
|
if (x<0) {
|
|
|
|
S = (S+f->numVerts-1)%f->numVerts;
|
|
|
|
cx = y;
|
|
|
|
cy = -x;
|
|
|
|
} else if (y<0) {
|
|
|
|
S = (S+1)%f->numVerts;
|
|
|
|
cx = -y;
|
|
|
|
cy = x;
|
|
|
|
} else {
|
|
|
|
cx = x;
|
|
|
|
cy = y;
|
|
|
|
}
|
|
|
|
return _face_getIFCo(f, levels, S, cx, cy, levels, dataSize);
|
|
|
|
}
|
2005-04-03 21:52:10 +00:00
|
|
|
static float *_face_getIFNoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize, int normalDataOffset) {
|
|
|
|
return (float*) ((byte*) _face_getIFCoEdge(f, e, lvl, eX, eY, levels, dataSize) + normalDataOffset);
|
|
|
|
}
|
2011-02-13 10:52:18 +00:00
|
|
|
static void _face_calcIFNo(CCGFace *f, int lvl, int S, int x, int y, float *no, int levels, int dataSize) {
|
2005-06-23 23:44:22 +00:00
|
|
|
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];
|
|
|
|
float length;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
|
|
|
|
|
2009-11-12 15:05:51 +00:00
|
|
|
if (length>EPSILON) {
|
2005-06-23 23:44:22 +00:00
|
|
|
float invLength = 1.f/length;
|
|
|
|
|
|
|
|
no[0] *= invLength;
|
|
|
|
no[1] *= invLength;
|
|
|
|
no[2] *= invLength;
|
|
|
|
} else {
|
|
|
|
NormZero(no);
|
|
|
|
}
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
static void _face_free(CCGFace *f, CCGSubSurf *ss) {
|
|
|
|
CCGSUBSURF_free(ss, f);
|
|
|
|
}
|
|
|
|
static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) {
|
|
|
|
int j;
|
|
|
|
for (j=0; j<f->numVerts; j++) {
|
2008-09-29 17:08:11 +00:00
|
|
|
_vert_remFace(FACE_getVerts(f)[j], f);
|
|
|
|
_edge_remFace(FACE_getEdges(f)[j], f);
|
2005-03-21 01:34:27 +00:00
|
|
|
FACE_getVerts(f)[j]->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
_face_free(f, ss);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!allocatorIFC) {
|
|
|
|
allocatorIFC = _getStandardAllocatorIFC();
|
|
|
|
allocator = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subdivLevels<1) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
|
|
|
|
|
|
|
|
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->meshIFC = *ifc;
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->subdivLevels = subdivLevels;
|
|
|
|
ss->numGrids = 0;
|
|
|
|
ss->allowEdgeCreation = 0;
|
2005-04-04 02:55:56 +00:00
|
|
|
ss->defaultCreaseValue = 0;
|
2005-08-20 09:16:09 +00:00
|
|
|
ss->defaultEdgeUserData = NULL;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
ss->useAgeCounts = 0;
|
|
|
|
ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
|
|
|
|
|
2005-04-03 21:52:10 +00:00
|
|
|
ss->calcVertNormals = 0;
|
|
|
|
ss->normalDataOffset = 0;
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
|
|
|
|
ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
|
|
|
|
|
|
|
|
ss->currentAge = 0;
|
|
|
|
|
|
|
|
ss->syncState = eSyncState_None;
|
|
|
|
|
|
|
|
ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
|
|
|
|
ss->lenTempArrays = 0;
|
|
|
|
ss->tempVerts = NULL;
|
|
|
|
ss->tempEdges = NULL;
|
|
|
|
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ccgSubSurf_free(CCGSubSurf *ss) {
|
|
|
|
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
|
|
|
|
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);
|
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(ss->tempVerts);
|
|
|
|
MEM_freeN(ss->tempEdges);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CCGSUBSURF_free(ss, ss->r);
|
|
|
|
CCGSUBSURF_free(ss, ss->q);
|
2005-08-20 09:16:09 +00:00
|
|
|
if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
_ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
|
|
|
|
_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
|
|
|
|
_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
|
|
|
|
|
|
|
|
CCGSUBSURF_free(ss, ss);
|
|
|
|
|
|
|
|
if (allocatorIFC.release) {
|
|
|
|
allocatorIFC.release(allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-20 09:16:09 +00:00
|
|
|
CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData) {
|
|
|
|
if (ss->defaultEdgeUserData) {
|
|
|
|
CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->allowEdgeCreation = !!allowEdgeCreation;
|
2005-04-04 02:55:56 +00:00
|
|
|
ss->defaultCreaseValue = defaultCreaseValue;
|
2005-08-20 09:16:09 +00:00
|
|
|
ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize);
|
|
|
|
|
|
|
|
if (defaultUserData) {
|
|
|
|
memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize);
|
|
|
|
} else {
|
|
|
|
memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2005-08-20 09:16:09 +00:00
|
|
|
void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r) {
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
if (allowEdgeCreation_r) *allowEdgeCreation_r = ss->allowEdgeCreation;
|
2005-08-20 09:16:09 +00:00
|
|
|
if (ss->allowEdgeCreation) {
|
|
|
|
if (defaultCreaseValue_r) *defaultCreaseValue_r = ss->defaultCreaseValue;
|
|
|
|
if (defaultUserData_r) memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
|
|
|
|
}
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) {
|
|
|
|
if (subdivisionLevels<=0) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
- shuffled editmesh derived function name/function
- added ModifierTypeInfo.freeData function
- added modifier_{new,free] utility function
- added ccgSubSurf_getUseAgeCounts to query info
- removed subsurf modifier faking (ME_SUBSURF flag is no
longer valid). subsurf modifier gets converted on file load
although there is obscure linked mesh situation where this
can go wrong, will fix shortly. this also means that some
places in the code that test/copy subsurf settings are broken
for the time being.
- shuffled modifier calculation to be simpler. note that
all modifiers are currently disabled in editmode (including
subsurf). don't worry, will return shortly.
- bug fix, build modifier didn't randomize meshes with only verts
- cleaned up subsurf_ccg and adapted for future editmode modifier
work
- added editmesh.derived{Cage,Final}, not used yet
- added SubsurfModifierData.{mCache,emCache}, will be used to cache
subsurf instead of caching in derivedmesh itself
- removed old subsurf buttons
- added do_modifiers_buttons to handle modifier events
- removed count_object counting of modifier (subsurfed) objects...
this would be nice to add back at some point but requires care.
probably requires rewrite of counting system.
New feature: Incremental Subsurf in Object Mode
The previous release introduce incremental subsurf calculation during
editmode but it was not turned on during object mode. In general it
does not make sense to have it always enabled during object mode because
it requires caching a fair amount of information about the mesh which
is a waste of memory unless the mesh is often recalculated.
However, for mesh's that have subsurfed armatures for example, or that
have other modifiers so that the mesh is essentially changing on every
frame, it makes a lot of sense to keep the subsurf'd object around and
that is what the new incremental subsurf modifier toggle is for. The
intent is that the user will enable this option for (a) a mesh that is
currently under active editing or (b) a mesh that is heavily updated
in the scene, such as a character.
I will try to write more about this feature for release, because it
has advantages and disadvantages that are not immediately obvious (the
first user reaction will be to turn it on for ever object, which is
probably not correct).
2005-07-21 20:30:33 +00:00
|
|
|
void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r)
|
|
|
|
{
|
|
|
|
*useAgeCounts_r = ss->useAgeCounts;
|
|
|
|
|
|
|
|
if (vertUserOffset_r) *vertUserOffset_r = ss->vertUserAgeOffset;
|
|
|
|
if (edgeUserOffset_r) *edgeUserOffset_r = ss->edgeUserAgeOffset;
|
|
|
|
if (faceUserOffset_r) *faceUserOffset_r = ss->faceUserAgeOffset;
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) {
|
|
|
|
if (useAgeCounts) {
|
|
|
|
if ( (vertUserOffset+4>ss->meshIFC.vertUserSize) ||
|
|
|
|
(edgeUserOffset+4>ss->meshIFC.edgeUserSize) ||
|
|
|
|
(faceUserOffset+4>ss->meshIFC.faceUserSize)) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} else {
|
|
|
|
ss->useAgeCounts = 1;
|
|
|
|
ss->vertUserAgeOffset = vertUserOffset;
|
|
|
|
ss->edgeUserAgeOffset = edgeUserOffset;
|
|
|
|
ss->faceUserAgeOffset = faceUserOffset;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ss->useAgeCounts = 0;
|
|
|
|
ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2005-04-03 21:52:10 +00:00
|
|
|
CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset) {
|
|
|
|
if (useVertNormals) {
|
|
|
|
if (normalDataOffset<0 || normalDataOffset+12>ss->meshIFC.vertDataSize) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} else {
|
|
|
|
ss->calcVertNormals = 1;
|
|
|
|
ss->normalDataOffset = normalDataOffset;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ss->calcVertNormals = 0;
|
|
|
|
ss->normalDataOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/***/
|
|
|
|
|
|
|
|
CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) {
|
|
|
|
if (ss->syncState!=eSyncState_None) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss->currentAge++;
|
|
|
|
|
|
|
|
ss->oldVMap = ss->vMap;
|
|
|
|
ss->oldEMap = ss->eMap;
|
|
|
|
ss->oldFMap = ss->fMap;
|
|
|
|
|
- added data arguments to deformer modifiers, in case someone wants
to write one that is based on geometry (and not just vertex position)
- added editmode versions of modifier deform/apply calls and flag
to tag modifiers that support editmode
- added isFinalCalc param to applyModifier, basically a switch to let
subsurf know if it is calc'ng orco or not (so it can deal with cache
appropriately). This is kinda hacky and perhaps I can come up with
a better solution (its also a waste to do a complete subdivide just
to get vertex locations).
- changed ccgsubsurf to not preallocate hash's to be approximately correct
size... this was probably not a big performance savings but means that
the order of faces returned by the iterator can vary after the first
call, this messes up orco calculation so dropped for time being.
- minor bug fix, meshes with only key didn't get vertex normals correctly
calc'd
- updated editmesh derivedmesh to support auxiliary locations
- changed mesh_calc_modifiers to alloc deformVerts on demand
- added editmesh_calc_modifiers for calculating editmesh cage and final
derivedmesh's
- bug fix, update shadedisplist to always calc colors (even if totvert==0)
- changed load_editMesh and make_edge to build me->medge even if totedge==0
(incremental subsurf checks this)
todo: add drawFacesTex for ccgderivedmesh
So, modifiers in editmode are back (which means auto-mirror
in edit mode works now) although still not finished. Currently
no cage is computed, the cage is always the base mesh (in
other words, Optimal edge style editing is off), and the final
mesh currently includes all modifiers that work in edit mode
(including lattice and curve). At some point there will be toggles
for which modifiers affect the final/cage editmode derivedmesh's.
Also, very nice new feature is that incremental subsurf in object
mode returns a ccgderivedmesh object instead of copying to a new
displistmesh. This can make a *huge* speed difference, and is very
nice for working with deformed armatures (esp. with only small
per frame changes).
2005-07-22 07:37:15 +00:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
ss->numGrids = 0;
|
|
|
|
|
|
|
|
ss->lenTempArrays = 12;
|
2010-02-08 15:01:11 +00:00
|
|
|
ss->tempVerts = MEM_mallocN(sizeof(*ss->tempVerts)*ss->lenTempArrays, "CCGSubsurf tempVerts");
|
|
|
|
ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges)*ss->lenTempArrays, "CCGSubsurf tempEdges");
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
ss->syncState = eSyncState_Vert;
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) {
|
|
|
|
if (ss->syncState!=eSyncState_None) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss->currentAge++;
|
|
|
|
|
|
|
|
ss->syncState = eSyncState_Partial;
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) {
|
|
|
|
if (ss->syncState!=eSyncState_Partial) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
} else {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
|
|
|
CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (!v || v->numFaces || v->numEdges) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} else {
|
|
|
|
*prevp = v->next;
|
|
|
|
_vert_free(v, ss);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) {
|
|
|
|
if (ss->syncState!=eSyncState_Partial) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
} else {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
2005-03-31 16:08:29 +00:00
|
|
|
CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (!e || e->numFaces) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} else {
|
|
|
|
*prevp = e->next;
|
|
|
|
_edge_unlinkMarkAndFree(e, ss);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) {
|
|
|
|
if (ss->syncState!=eSyncState_Partial) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
} else {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
|
|
|
CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (!f) {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
} else {
|
|
|
|
*prevp = f->next;
|
|
|
|
_face_unlinkMarkAndFree(f, ss);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2006-01-10 11:36:57 +00:00
|
|
|
CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r) {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
CCGVert *v = NULL;
|
2006-01-10 11:36:57 +00:00
|
|
|
short seamflag = (seam)? Vert_eSeam: 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (ss->syncState==eSyncState_Partial) {
|
|
|
|
v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
|
|
|
|
if (!v) {
|
2008-09-29 17:08:11 +00:00
|
|
|
v = _vert_new(vHDL, ss);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
|
2005-03-21 01:34:27 +00:00
|
|
|
_ehash_insert(ss->vMap, (EHEntry*) v);
|
2006-01-10 11:36:57 +00:00
|
|
|
v->flags = Vert_eEffected|seamflag;
|
|
|
|
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int i, j;
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
|
2006-01-10 11:36:57 +00:00
|
|
|
v->flags = Vert_eEffected|seamflag;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[i];
|
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
for (i=0; i<v->numFaces; i++) {
|
|
|
|
CCGFace *f = v->faces[i];
|
|
|
|
for (j=0; j<f->numVerts; j++) {
|
|
|
|
FACE_getVerts(f)[j]->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ss->syncState!=eSyncState_Vert) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
|
|
|
|
if (!v) {
|
2008-09-29 17:08:11 +00:00
|
|
|
v = _vert_new(vHDL, ss);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
|
2005-03-21 01:34:27 +00:00
|
|
|
_ehash_insert(ss->vMap, (EHEntry*) v);
|
2006-01-10 11:36:57 +00:00
|
|
|
v->flags = Vert_eEffected|seamflag;
|
|
|
|
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = v->next;
|
|
|
|
_ehash_insert(ss->vMap, (EHEntry*) v);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
|
2006-01-10 11:36:57 +00:00
|
|
|
v->flags = Vert_eEffected|Vert_eChanged|seamflag;
|
2005-03-21 01:34:27 +00:00
|
|
|
} else {
|
|
|
|
*prevp = v->next;
|
|
|
|
_ehash_insert(ss->vMap, (EHEntry*) v);
|
|
|
|
v->flags = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
if (v_r) *v_r = v;
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r) {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
CCGEdge *e = NULL, *eNew;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (ss->syncState==eSyncState_Partial) {
|
|
|
|
e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
|
2005-04-01 02:07:34 +00:00
|
|
|
if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1 || crease!=e->crease) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
|
|
|
|
CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
eNew = _edge_new(eHDL, v0, v1, crease, ss);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (e) {
|
|
|
|
*prevp = eNew;
|
|
|
|
eNew->next = e->next;
|
|
|
|
|
|
|
|
_edge_unlinkMarkAndFree(e, ss);
|
|
|
|
} else {
|
|
|
|
_ehash_insert(ss->eMap, (EHEntry*) eNew);
|
|
|
|
}
|
|
|
|
|
|
|
|
eNew->v0->flags |= Vert_eEffected;
|
|
|
|
eNew->v1->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ss->syncState==eSyncState_Vert) {
|
|
|
|
ss->syncState = eSyncState_Edge;
|
|
|
|
} else if (ss->syncState!=eSyncState_Edge) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
|
2005-04-01 02:07:34 +00:00
|
|
|
if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1|| e->crease!=crease) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
|
|
|
|
CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
|
2008-09-29 17:08:11 +00:00
|
|
|
e = _edge_new(eHDL, v0, v1, crease, ss);
|
2005-03-21 01:34:27 +00:00
|
|
|
_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);
|
|
|
|
e->flags = 0;
|
|
|
|
if ((e->v0->flags|e->v1->flags)&Vert_eChanged) {
|
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
if (e_r) *e_r = e;
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r) {
|
2005-03-27 14:37:00 +00:00
|
|
|
void **prevp;
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
CCGFace *f = NULL, *fNew;
|
2005-03-21 01:34:27 +00:00
|
|
|
int j, k, topologyChanged = 0;
|
|
|
|
|
|
|
|
if (numVerts>ss->lenTempArrays) {
|
|
|
|
ss->lenTempArrays = (numVerts<ss->lenTempArrays*2)?ss->lenTempArrays*2:numVerts;
|
2010-02-08 15:01:11 +00:00
|
|
|
ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts)*ss->lenTempArrays);
|
|
|
|
ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges)*ss->lenTempArrays);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ss->syncState==eSyncState_Partial) {
|
|
|
|
f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
|
|
|
|
|
|
|
|
for (k=0; k<numVerts; k++) {
|
|
|
|
ss->tempVerts[k] = _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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f) {
|
|
|
|
if ( f->numVerts!=numVerts ||
|
|
|
|
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
|
|
|
|
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
|
|
|
|
topologyChanged = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f || topologyChanged) {
|
2008-09-29 17:08:11 +00:00
|
|
|
fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
if (f) {
|
|
|
|
ss->numGrids += numVerts - f->numVerts;
|
|
|
|
|
|
|
|
*prevp = fNew;
|
|
|
|
fNew->next = f->next;
|
|
|
|
|
|
|
|
_face_unlinkMarkAndFree(f, ss);
|
|
|
|
} else {
|
|
|
|
ss->numGrids += numVerts;
|
|
|
|
_ehash_insert(ss->fMap, (EHEntry*) fNew);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k=0; k<numVerts; k++)
|
|
|
|
FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ss->syncState==eSyncState_Vert || ss->syncState==eSyncState_Edge) {
|
|
|
|
ss->syncState = eSyncState_Face;
|
|
|
|
} else if (ss->syncState!=eSyncState_Face) {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
|
|
|
|
|
|
|
|
for (k=0; k<numVerts; k++) {
|
|
|
|
ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
|
2005-08-03 19:27:19 +00:00
|
|
|
|
|
|
|
if (!ss->tempVerts[k])
|
|
|
|
return eCCGError_InvalidValue;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
for (k=0; k<numVerts; k++) {
|
|
|
|
ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
|
|
|
|
|
2005-08-03 19:27:19 +00:00
|
|
|
if (!ss->tempEdges[k]) {
|
|
|
|
if (ss->allowEdgeCreation) {
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) -1, ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts], ss->defaultCreaseValue, ss);
|
2005-08-03 19:27:19 +00:00
|
|
|
_ehash_insert(ss->eMap, (EHEntry*) e);
|
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
2005-08-20 09:16:09 +00:00
|
|
|
if (ss->meshIFC.edgeUserSize) {
|
|
|
|
memcpy(ccgSubSurf_getEdgeUserData(ss, e), ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
|
|
|
|
}
|
2005-08-03 19:27:19 +00:00
|
|
|
} else {
|
|
|
|
return eCCGError_InvalidValue;
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f) {
|
|
|
|
if ( f->numVerts!=numVerts ||
|
|
|
|
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
|
|
|
|
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
|
|
|
|
topologyChanged = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f || topologyChanged) {
|
2008-09-29 17:08:11 +00:00
|
|
|
f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
|
2005-03-21 01:34:27 +00:00
|
|
|
_ehash_insert(ss->fMap, (EHEntry*) f);
|
|
|
|
ss->numGrids += numVerts;
|
|
|
|
|
|
|
|
for (k=0; k<numVerts; k++)
|
|
|
|
FACE_getVerts(f)[k]->flags |= Vert_eEffected;
|
|
|
|
} else {
|
|
|
|
*prevp = f->next;
|
|
|
|
_ehash_insert(ss->fMap, (EHEntry*) f);
|
|
|
|
f->flags = 0;
|
|
|
|
ss->numGrids += f->numVerts;
|
|
|
|
|
|
|
|
for (j=0; j<f->numVerts; j++) {
|
|
|
|
if (FACE_getVerts(f)[j]->flags&Vert_eChanged) {
|
|
|
|
for (k=0; k<f->numVerts; k++)
|
|
|
|
FACE_getVerts(f)[k]->flags |= Vert_eEffected;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
- convert all DerivedMesh map functions to use index based
mapping (instead of Edit{Vert,Edge,Face} pointers)
- dropped convertToDispListMeshMapped (whew, glad of it too)
- added DerivedMesh drawMappedFaces function
- dropped EM suffix for DerivedMesh functions, it was neither
particularly correct nor descriptive
- converted test_index_mface to test_index_face that also corrects
MCol and TFace. Good thing we had three versions of this routine,
you never know when one might burn down.
- removed flipnorm_mesh, not used anymore (and was incorrect to
boot)
- Getting face select to work with modifiers turned out to be much
more complicated than expected. Reworked mapping architecture for
modifiers - basically elements in a DispListMesh are now required
to be stored in an order that corresponds exactly to original
ordering. MVert/MEdge/MFace all have a new flag ME_XXX_STEPINDEX
that is set on each element that is set on the first derived element
of each original element. I can't say the code to follow these
requirements for subsurf is particularly transparent, but on the
upside it is a reasonably consistent and simple system that is memory
efficient and allows keeping the DispListMesh structure.
- rewrote mirror modifier to be simpler/conform to new requirements
for mapped DispListMesh structure. This also means that mirror interacts
much better with incremental subsurf calculation (it used to recalc
one entire side on any topology change, now it generally avoids that).
- added EM_{init,free}_index_arrays and EM_get_{vert,edge,face}_for_index
functions to handle mapping indices back into appropriate EditMesh
structures.
- bug fix, make edges didn't recalc object data
- bug fix, initial image assignment to TFace's didn't recalc object data
- new feature, added circle select support for FACESELECT
- bug fix, creating new faces in editmode duplicated the TFACE active
flag - but there should only be one active tface
- bug fix, possible crash when deleting all faces in faceselect mode
on mesh with tfaces...
Still todo: TFace edge drawing is still not always correct in face
mode, in particular with a mirror modifier when mesh has edges (and
no preceeding subsurf). Have not yet decided how to deal with this.
Best solution is probably to do switch to meshes all having MEdge's,
in which case I can get rid of TFace edge flags (and need to recalc
modifiers on tface selection change).
2005-08-20 03:08:23 +00:00
|
|
|
if (f_r) *f_r = f;
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ccgSubSurf__sync(CCGSubSurf *ss);
|
|
|
|
CCGError ccgSubSurf_processSync(CCGSubSurf *ss) {
|
|
|
|
if (ss->syncState==eSyncState_Partial) {
|
|
|
|
ss->syncState = eSyncState_None;
|
|
|
|
|
|
|
|
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);
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(ss->tempEdges);
|
|
|
|
MEM_freeN(ss->tempVerts);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
ss->lenTempArrays = 0;
|
|
|
|
|
|
|
|
ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
|
|
|
|
ss->tempVerts = NULL;
|
|
|
|
ss->tempEdges = NULL;
|
|
|
|
|
|
|
|
ss->syncState = eSyncState_None;
|
|
|
|
|
|
|
|
ccgSubSurf__sync(ss);
|
|
|
|
} else {
|
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2010-01-30 09:32:05 +00:00
|
|
|
#define VERT_getNo(e, lvl) _vert_getNo(e, lvl, vertDataSize, normalDataOffset)
|
|
|
|
#define EDGE_getNo(e, lvl, x) _edge_getNo(e, lvl, x, vertDataSize, normalDataOffset)
|
2009-11-25 12:27:21 +00:00
|
|
|
#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)
|
2010-01-30 09:32:05 +00:00
|
|
|
#define FACE_getIENo(f, lvl, S, x) _face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset)
|
2009-11-25 12:27:21 +00:00
|
|
|
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 = 1 + (1<<lvl);
|
|
|
|
int gridSize = 1 + (1<<(lvl-1));
|
|
|
|
int normalDataOffset = ss->normalDataOffset;
|
|
|
|
int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-11-25 12:27:21 +00:00
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
|
|
|
|
CCGFace *f = (CCGFace*) effectedF[ptrIdx];
|
|
|
|
int S, x, y;
|
2009-12-03 18:35:37 +00:00
|
|
|
float no[3];
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
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 length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
|
|
|
|
|
2009-11-25 17:51:16 +00:00
|
|
|
if (length>EPSILON) {
|
2009-11-25 12:27:21 +00:00
|
|
|
float invLength = 1.0f/length;
|
|
|
|
no[0] *= invLength;
|
|
|
|
no[1] *= invLength;
|
|
|
|
no[2] *= invLength;
|
|
|
|
} else {
|
|
|
|
NormZero(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];
|
|
|
|
|
|
|
|
for (x=1; x<edgeSize-1; x++) {
|
|
|
|
NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
|
|
|
|
_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<e->numFaces-1; i++) {
|
|
|
|
CCGFace *f = e->faces[i];
|
|
|
|
|
|
|
|
for (x=1; x<edgeSize-1; x++) {
|
|
|
|
NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
|
|
|
|
_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-11-25 12:27:21 +00:00
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
|
|
|
|
CCGFace *f = (CCGFace*) effectedF[ptrIdx];
|
2009-12-03 18:35:37 +00:00
|
|
|
int S, x, y;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
|
|
|
|
|
2009-11-25 17:51:16 +00:00
|
|
|
if (length>EPSILON) {
|
2009-11-25 12:27:21 +00:00
|
|
|
float invLength = 1.0f/length;
|
|
|
|
no[0] *= invLength;
|
|
|
|
no[1] *= invLength;
|
|
|
|
no[2] *= invLength;
|
|
|
|
} else {
|
|
|
|
NormZero(no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-01-30 09:32:05 +00:00
|
|
|
|
|
|
|
VertDataCopy((float*)((byte*)FACE_getCenterData(f) + normalDataOffset),
|
|
|
|
FACE_getIFNo(f, lvl, S, 0, 0));
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (x=0; x<edgeSize; x++)
|
|
|
|
NormCopy(EDGE_getNo(e, lvl, x),
|
|
|
|
_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2011-03-30 02:05:10 +00:00
|
|
|
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++) {
|
|
|
|
NormZero(EDGE_getNo(e, lvl, x));
|
|
|
|
}
|
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef FACE_getIFNo
|
|
|
|
|
|
|
|
#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize)
|
|
|
|
#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize)
|
|
|
|
#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 = 1 + (1<<curLvl);
|
|
|
|
int gridSize = 1 + (1<<(curLvl-1));
|
|
|
|
int nextLvl = curLvl+1;
|
2009-12-03 18:35:37 +00:00
|
|
|
int ptrIdx, cornerIdx, i;
|
2009-11-25 12:27:21 +00:00
|
|
|
int vertDataSize = ss->meshIFC.vertDataSize;
|
2009-12-03 18:35:37 +00:00
|
|
|
void *q = ss->q, *r = ss->r;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-11-25 12:27:21 +00:00
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
|
|
|
|
CCGFace *f = (CCGFace*) effectedF[ptrIdx];
|
2009-12-03 18:35:37 +00:00
|
|
|
int S, x, y;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
/* interior face midpoints
|
|
|
|
* o 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;
|
|
|
|
void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
|
|
|
|
void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
|
|
|
|
void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
|
|
|
|
void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
|
|
|
|
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* interior edge midpoints
|
|
|
|
* o old interior edge points
|
|
|
|
* o new interior face midpoints
|
|
|
|
*/
|
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
for (x=0; x<gridSize-1; x++) {
|
|
|
|
int fx = x*2 + 1;
|
|
|
|
void *co0 = FACE_getIECo(f, curLvl, S, x+0);
|
|
|
|
void *co1 = FACE_getIECo(f, curLvl, S, x+1);
|
|
|
|
void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
|
|
|
|
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
|
|
|
|
void *co = FACE_getIECo(f, nextLvl, S, fx);
|
|
|
|
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* interior face interior edge midpoints
|
|
|
|
* o old interior face points
|
|
|
|
* o 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;
|
|
|
|
void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
|
|
|
|
void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
|
|
|
|
void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
|
|
|
|
void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
|
|
|
|
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* horizontal */
|
|
|
|
for (y=1; y<gridSize-1; y++) {
|
|
|
|
for (x=0; x<gridSize-1; x++) {
|
|
|
|
int fx = x*2+1;
|
|
|
|
int fy = y*2;
|
|
|
|
void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
|
|
|
|
void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
|
|
|
|
void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
|
|
|
|
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
|
|
|
|
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exterior edge midpoints
|
|
|
|
* o old exterior edge points
|
|
|
|
* o new interior face midpoints
|
|
|
|
*/
|
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
|
|
|
|
CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
|
|
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
2009-12-03 18:35:37 +00:00
|
|
|
int x, j;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2011-03-27 17:22:04 +00:00
|
|
|
if (_edge_isBoundary(e) || sharpness > 1.0f) {
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=0; x<edgeSize-1; x++) {
|
|
|
|
int fx = x*2 + 1;
|
|
|
|
void *co0 = EDGE_getCo(e, curLvl, x+0);
|
|
|
|
void *co1 = EDGE_getCo(e, curLvl, x+1);
|
|
|
|
void *co = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
|
|
|
|
VertDataCopy(co, co0);
|
|
|
|
VertDataAdd(co, co1);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(co, 0.5f);
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (x=0; x<edgeSize-1; x++) {
|
|
|
|
int fx = x*2 + 1;
|
|
|
|
void *co0 = EDGE_getCo(e, curLvl, x+0);
|
|
|
|
void *co1 = EDGE_getCo(e, curLvl, x+1);
|
|
|
|
void *co = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
int numFaces = 0;
|
|
|
|
|
|
|
|
VertDataCopy(q, co0);
|
|
|
|
VertDataAdd(q, co1);
|
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<e->numFaces; j++) {
|
|
|
|
CCGFace *f = e->faces[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
|
|
|
|
numFaces++;
|
|
|
|
}
|
|
|
|
|
|
|
|
VertDataMulN(q, 1.0f/(2.0f+numFaces));
|
|
|
|
|
|
|
|
VertDataCopy(r, co0);
|
|
|
|
VertDataAdd(r, co1);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(r, 0.5f);
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
VertDataCopy(co, q);
|
|
|
|
VertDataSub(r, q);
|
|
|
|
VertDataMulN(r, sharpness);
|
|
|
|
VertDataAdd(co, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exterior vertex shift
|
|
|
|
* o old vertex points (shifting)
|
|
|
|
* o old exterior edge points
|
|
|
|
* o new interior face midpoints
|
|
|
|
*/
|
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
|
|
|
|
CCGVert *v = (CCGVert*) effectedV[ptrIdx];
|
|
|
|
void *co = VERT_getCo(v, curLvl);
|
|
|
|
void *nCo = VERT_getCo(v, nextLvl);
|
|
|
|
int sharpCount = 0, allSharp = 1;
|
|
|
|
float avgSharpness = 0.0;
|
2009-12-03 18:35:37 +00:00
|
|
|
int j, seam = VERT_seam(v), seamEdges = 0;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<v->numEdges; j++) {
|
|
|
|
CCGEdge *e = v->edges[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
2011-03-27 17:22:04 +00:00
|
|
|
if (avgSharpness > 1.0f) {
|
|
|
|
avgSharpness = 1.0f;
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-05 12:04:06 +00:00
|
|
|
if (seamEdges < 2 || seamEdges != v->numEdges)
|
2009-11-25 12:27:21 +00:00
|
|
|
seam = 0;
|
|
|
|
|
|
|
|
if (!v->numEdges) {
|
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
} else if (_vert_isBoundary(v)) {
|
|
|
|
int numBoundary = 0;
|
|
|
|
|
|
|
|
VertDataZero(r);
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<v->numEdges; j++) {
|
|
|
|
CCGEdge *e = v->edges[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
if (_edge_isBoundary(e)) {
|
|
|
|
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
|
|
|
|
numBoundary++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VertDataCopy(nCo, co);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(nCo, 0.75f);
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataMulN(r, 0.25f/numBoundary);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
} else {
|
|
|
|
int cornerIdx = (1 + (1<<(curLvl))) - 2;
|
|
|
|
int numEdges = 0, numFaces = 0;
|
|
|
|
|
|
|
|
VertDataZero(q);
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<v->numFaces; j++) {
|
|
|
|
CCGFace *f = v->faces[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
|
|
|
|
numFaces++;
|
|
|
|
}
|
|
|
|
VertDataMulN(q, 1.0f/numFaces);
|
|
|
|
VertDataZero(r);
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<v->numEdges; j++) {
|
|
|
|
CCGEdge *e = v->edges[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
|
|
|
|
numEdges++;
|
|
|
|
}
|
|
|
|
VertDataMulN(r, 1.0f/numEdges);
|
|
|
|
|
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
VertDataMulN(nCo, numEdges-2.0f);
|
|
|
|
VertDataAdd(nCo, q);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
VertDataMulN(nCo, 1.0f/numEdges);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sharpCount>1 && v->numFaces) || seam) {
|
|
|
|
VertDataZero(q);
|
|
|
|
|
|
|
|
if (seam) {
|
|
|
|
avgSharpness = 1.0f;
|
|
|
|
sharpCount = seamEdges;
|
|
|
|
allSharp = 1;
|
|
|
|
}
|
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<v->numEdges; j++) {
|
|
|
|
CCGEdge *e = v->edges[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
|
|
|
|
if (seam) {
|
|
|
|
if (_edge_isBoundary(e))
|
|
|
|
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
|
2011-03-27 17:22:04 +00:00
|
|
|
} else if (sharpness != 0.0f) {
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VertDataMulN(q, (float) 1/sharpCount);
|
|
|
|
|
|
|
|
if (sharpCount!=2 || allSharp) {
|
|
|
|
// q = q + (co-q)*avgSharpness
|
|
|
|
VertDataCopy(r, co);
|
|
|
|
VertDataSub(r, q);
|
|
|
|
VertDataMulN(r, avgSharpness);
|
|
|
|
VertDataAdd(q, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// r = co*.75 + q*.25
|
|
|
|
VertDataCopy(r, co);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(r, .75f);
|
|
|
|
VertDataMulN(q, .25f);
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(r, q);
|
|
|
|
|
|
|
|
// nCo = nCo + (r-nCo)*avgSharpness
|
|
|
|
VertDataSub(r, nCo);
|
|
|
|
VertDataMulN(r, avgSharpness);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* exterior edge interior shift
|
|
|
|
* o old exterior edge midpoints (shifting)
|
|
|
|
* o old exterior edge midpoints
|
|
|
|
* o 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;
|
2009-12-03 18:35:37 +00:00
|
|
|
int x, j;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
if (sharpness!=0.0f) {
|
|
|
|
sharpCount = 2;
|
|
|
|
avgSharpness += sharpness;
|
|
|
|
|
2011-03-27 17:22:04 +00:00
|
|
|
if (avgSharpness > 1.0f) {
|
|
|
|
avgSharpness = 1.0f;
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sharpCount = 0;
|
|
|
|
avgSharpness = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
|
|
|
|
for (x=1; x<edgeSize-1; x++) {
|
|
|
|
int fx = x*2;
|
|
|
|
void *co = EDGE_getCo(e, curLvl, x);
|
|
|
|
void *nCo = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
|
|
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(r, 0.5f);
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataCopy(nCo, co);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(nCo, 0.75f);
|
|
|
|
VertDataMulN(r, 0.25f);
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (x=1; x<edgeSize-1; x++) {
|
|
|
|
int fx = x*2;
|
|
|
|
void *co = EDGE_getCo(e, curLvl, x);
|
|
|
|
void *nCo = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
int numFaces = 0;
|
|
|
|
|
|
|
|
VertDataZero(q);
|
|
|
|
VertDataZero(r);
|
|
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
|
|
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
|
2009-12-03 18:35:37 +00:00
|
|
|
for (j=0; j<e->numFaces; j++) {
|
|
|
|
CCGFace *f = e->faces[j];
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
|
|
|
|
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
|
|
|
|
|
|
|
|
VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
|
|
|
|
numFaces++;
|
|
|
|
}
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(q, 1.0f/(numFaces*2.0f));
|
|
|
|
VertDataMulN(r, 1.0f/(2.0f + numFaces));
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
VertDataMulN(nCo, (float) numFaces);
|
|
|
|
VertDataAdd(nCo, q);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
VertDataMulN(nCo, 1.0f/(2+numFaces));
|
|
|
|
|
|
|
|
if (sharpCount==2) {
|
|
|
|
VertDataCopy(q, co);
|
|
|
|
VertDataMulN(q, 6.0f);
|
|
|
|
VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
|
|
|
|
VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
|
|
|
|
VertDataMulN(q, 1/8.0f);
|
|
|
|
|
|
|
|
VertDataSub(q, nCo);
|
|
|
|
VertDataMulN(q, avgSharpness);
|
|
|
|
VertDataAdd(nCo, q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-12-03 18:35:37 +00:00
|
|
|
{
|
|
|
|
void *q, *r;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp critical
|
2009-12-03 18:35:37 +00:00
|
|
|
{
|
2010-02-08 15:01:11 +00:00
|
|
|
q = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q");
|
|
|
|
r = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r");
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp for schedule(static)
|
2009-12-03 18:35:37 +00:00
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
|
|
|
|
CCGFace *f = (CCGFace*) effectedF[ptrIdx];
|
|
|
|
int S, x, y;
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
/* interior center point shift
|
|
|
|
* o old face center point (shifting)
|
|
|
|
* o old interior edge points
|
2009-11-25 12:27:21 +00:00
|
|
|
* o new interior face midpoints
|
|
|
|
*/
|
2009-12-03 18:35:37 +00:00
|
|
|
VertDataZero(q);
|
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
|
|
|
|
}
|
|
|
|
VertDataMulN(q, 1.0f/f->numVerts);
|
|
|
|
VertDataZero(r);
|
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
|
|
|
|
}
|
|
|
|
VertDataMulN(r, 1.0f/f->numVerts);
|
|
|
|
|
|
|
|
VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
|
|
|
|
VertDataAdd(FACE_getCenterData(f), q);
|
|
|
|
VertDataAdd(FACE_getCenterData(f), r);
|
|
|
|
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
|
|
|
|
|
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
/* interior face shift
|
|
|
|
* o old interior face point (shifting)
|
|
|
|
* o new interior edge midpoints
|
|
|
|
* o 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;
|
|
|
|
void *co = FACE_getIFCo(f, curLvl, S, x, y);
|
|
|
|
void *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));
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
VertDataSub(nCo, q);
|
|
|
|
VertDataMulN(nCo, 0.25f);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* interior edge interior shift
|
|
|
|
* o old interior edge point (shifting)
|
|
|
|
* o new interior edge midpoints
|
|
|
|
* o new interior face midpoints
|
|
|
|
*/
|
|
|
|
for (x=1; x<gridSize-1; x++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
int fx = x*2;
|
2009-12-03 18:35:37 +00:00
|
|
|
void *co = FACE_getIECo(f, curLvl, S, x);
|
|
|
|
void *nCo = FACE_getIECo(f, nextLvl, S, fx);
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
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));
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2009-12-03 18:35:37 +00:00
|
|
|
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));
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
VertDataSub(nCo, q);
|
|
|
|
VertDataMulN(nCo, 0.25f);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
}
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp critical
|
2009-12-03 18:35:37 +00:00
|
|
|
{
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(q);
|
|
|
|
MEM_freeN(r);
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy down */
|
|
|
|
edgeSize = 1 + (1<<(nextLvl));
|
|
|
|
gridSize = 1 + (1<<((nextLvl)-1));
|
|
|
|
cornerIdx = gridSize-1;
|
2009-12-03 18:35:37 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numEffectedE; i++) {
|
|
|
|
CCGEdge *e = effectedE[i];
|
|
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
|
|
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
|
|
|
|
}
|
2009-12-03 18:35:37 +00:00
|
|
|
|
2010-06-22 15:09:41 +00:00
|
|
|
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numEffectedF; i++) {
|
|
|
|
CCGFace *f = effectedF[i];
|
2009-12-03 18:35:37 +00:00
|
|
|
int S, x;
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
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), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
|
|
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
|
|
|
|
for (x=1; x<gridSize-1; x++) {
|
|
|
|
void *co = FACE_getIECo(f, nextLvl, S, x);
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
|
|
|
|
}
|
|
|
|
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));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
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;
|
2009-11-25 12:27:21 +00:00
|
|
|
int i, j, ptrIdx, S;
|
2005-03-21 01:34:27 +00:00
|
|
|
int curLvl, nextLvl;
|
2009-11-25 12:27:21 +00:00
|
|
|
void *q = ss->q, *r = ss->r;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
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");
|
2005-03-21 01:34:27 +00:00
|
|
|
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);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataZero(co);
|
2005-03-21 01:34:27 +00:00
|
|
|
for (i=0; i<f->numVerts; i++) {
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(co, 1.0f/f->numVerts);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
|
|
|
f->flags = 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
|
|
|
|
CCGEdge *e = effectedE[ptrIdx];
|
|
|
|
void *co = EDGE_getCo(e, nextLvl, 1);
|
2007-06-09 10:51:02 +00:00
|
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2011-03-27 17:22:04 +00:00
|
|
|
if (_edge_isBoundary(e) || sharpness >= 1.0f) {
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(co, VERT_getCo(e->v0, curLvl));
|
|
|
|
VertDataAdd(co, VERT_getCo(e->v1, curLvl));
|
|
|
|
VertDataMulN(co, 0.5f);
|
2005-03-22 06:11:25 +00:00
|
|
|
} else {
|
|
|
|
int numFaces = 0;
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(q, VERT_getCo(e->v0, curLvl));
|
|
|
|
VertDataAdd(q, VERT_getCo(e->v1, curLvl));
|
2005-03-22 06:11:25 +00:00
|
|
|
for (i=0; i<e->numFaces; i++) {
|
|
|
|
CCGFace *f = e->faces[i];
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(q, FACE_getCenterData(f));
|
2005-03-22 06:11:25 +00:00
|
|
|
numFaces++;
|
|
|
|
}
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(q, 1.0f/(2.0f+numFaces));
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(r, VERT_getCo(e->v0, curLvl));
|
|
|
|
VertDataAdd(r, VERT_getCo(e->v1, curLvl));
|
|
|
|
VertDataMulN(r, 0.5f);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(co, q);
|
|
|
|
VertDataSub(r, q);
|
|
|
|
VertDataMulN(r, sharpness);
|
|
|
|
VertDataAdd(co, r);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
|
2005-06-23 23:44:22 +00:00
|
|
|
// edge flags cleared later
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
|
|
|
|
CCGVert *v = effectedV[ptrIdx];
|
|
|
|
void *co = VERT_getCo(v, curLvl);
|
|
|
|
void *nCo = VERT_getCo(v, nextLvl);
|
2005-04-04 03:38:21 +00:00
|
|
|
int sharpCount = 0, allSharp = 1;
|
2005-03-22 06:11:25 +00:00
|
|
|
float avgSharpness = 0.0;
|
2008-09-29 17:08:11 +00:00
|
|
|
int seam = VERT_seam(v), seamEdges = 0;
|
2005-03-22 06:11:25 +00:00
|
|
|
|
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[i];
|
2007-06-09 10:51:02 +00:00
|
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2006-01-10 11:36:57 +00:00
|
|
|
if (seam && _edge_isBoundary(e))
|
|
|
|
seamEdges++;
|
|
|
|
|
2005-03-22 06:11:25 +00:00
|
|
|
if (sharpness!=0.0f) {
|
|
|
|
sharpCount++;
|
|
|
|
avgSharpness += sharpness;
|
2005-04-04 03:38:21 +00:00
|
|
|
} else {
|
|
|
|
allSharp = 0;
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-01 17:07:24 +00:00
|
|
|
if(sharpCount) {
|
|
|
|
avgSharpness /= sharpCount;
|
2011-03-27 17:22:04 +00:00
|
|
|
if (avgSharpness > 1.0f) {
|
|
|
|
avgSharpness = 1.0f;
|
2008-11-01 17:07:24 +00:00
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
|
2011-01-05 12:04:06 +00:00
|
|
|
if (seamEdges < 2 || seamEdges != v->numEdges)
|
2006-01-10 11:36:57 +00:00
|
|
|
seam = 0;
|
|
|
|
|
2005-04-01 02:52:55 +00:00
|
|
|
if (!v->numEdges) {
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(nCo, co);
|
2005-04-01 02:52:55 +00:00
|
|
|
} else if (_vert_isBoundary(v)) {
|
2005-03-22 06:11:25 +00:00
|
|
|
int numBoundary = 0;
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataZero(r);
|
2005-03-22 06:11:25 +00:00
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[i];
|
|
|
|
if (_edge_isBoundary(e)) {
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
|
2005-03-22 06:11:25 +00:00
|
|
|
numBoundary++;
|
|
|
|
}
|
|
|
|
}
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(nCo, co);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(nCo, 0.75f);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(r, 0.25f/numBoundary);
|
|
|
|
VertDataAdd(nCo, r);
|
2005-03-22 06:11:25 +00:00
|
|
|
} else {
|
|
|
|
int numEdges = 0, numFaces = 0;
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataZero(q);
|
2005-03-22 06:11:25 +00:00
|
|
|
for (i=0; i<v->numFaces; i++) {
|
|
|
|
CCGFace *f = v->faces[i];
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(q, FACE_getCenterData(f));
|
2005-03-22 06:11:25 +00:00
|
|
|
numFaces++;
|
|
|
|
}
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(q, 1.0f/numFaces);
|
|
|
|
VertDataZero(r);
|
2005-03-22 06:11:25 +00:00
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[i];
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
|
2005-03-22 06:11:25 +00:00
|
|
|
numEdges++;
|
|
|
|
}
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(r, 1.0f/numEdges);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(nCo, co);
|
|
|
|
VertDataMulN(nCo, numEdges-2.0f);
|
|
|
|
VertDataAdd(nCo, q);
|
|
|
|
VertDataAdd(nCo, r);
|
|
|
|
VertDataMulN(nCo, 1.0f/numEdges);
|
2005-04-01 02:52:55 +00:00
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2008-03-21 03:08:04 +00:00
|
|
|
if (sharpCount>1 || seam) {
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataZero(q);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2006-01-10 11:36:57 +00:00
|
|
|
if (seam) {
|
|
|
|
avgSharpness = 1.0f;
|
|
|
|
sharpCount = seamEdges;
|
|
|
|
allSharp = 1;
|
|
|
|
}
|
|
|
|
|
2005-04-01 02:52:55 +00:00
|
|
|
for (i=0; i<v->numEdges; i++) {
|
|
|
|
CCGEdge *e = v->edges[i];
|
2007-06-09 10:51:02 +00:00
|
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2006-01-10 11:36:57 +00:00
|
|
|
if (seam) {
|
|
|
|
if (_edge_isBoundary(e)) {
|
|
|
|
CCGVert *oV = _edge_getOtherVert(e, v);
|
|
|
|
VertDataAdd(q, VERT_getCo(oV, curLvl));
|
|
|
|
}
|
2011-03-27 17:22:04 +00:00
|
|
|
} else if (sharpness != 0.0f) {
|
2005-04-01 02:52:55 +00:00
|
|
|
CCGVert *oV = _edge_getOtherVert(e, v);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(q, VERT_getCo(oV, curLvl));
|
2005-04-01 02:52:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataMulN(q, (float) 1/sharpCount);
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2005-04-04 03:38:21 +00:00
|
|
|
if (sharpCount!=2 || allSharp) {
|
2005-04-01 02:52:55 +00:00
|
|
|
// q = q + (co-q)*avgSharpness
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(r, co);
|
|
|
|
VertDataSub(r, q);
|
|
|
|
VertDataMulN(r, avgSharpness);
|
|
|
|
VertDataAdd(q, r);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
2005-04-01 02:52:55 +00:00
|
|
|
|
|
|
|
// r = co*.75 + q*.25
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(r, co);
|
2011-03-27 17:22:04 +00:00
|
|
|
VertDataMulN(r, 0.75f);
|
|
|
|
VertDataMulN(q, 0.25f);
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataAdd(r, q);
|
2005-04-01 02:52:55 +00:00
|
|
|
|
|
|
|
// nCo = nCo + (r-nCo)*avgSharpness
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataSub(r, nCo);
|
|
|
|
VertDataMulN(r, avgSharpness);
|
|
|
|
VertDataAdd(nCo, r);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
|
2005-06-23 23:44:22 +00:00
|
|
|
// vert flags cleared later
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
|
|
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
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];
|
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
|
|
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2005-04-04 05:21:20 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (curLvl=1; curLvl<subdivLevels; curLvl++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__calcSubdivLevel(ss,
|
|
|
|
effectedV, effectedE, effectedF,
|
|
|
|
numEffectedV, numEffectedE, numEffectedF, curLvl);
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
if (ss->calcVertNormals)
|
|
|
|
ccgSubSurf__calcVertNormals(ss,
|
|
|
|
effectedV, effectedE, effectedF,
|
|
|
|
numEffectedV, numEffectedE, numEffectedF);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(effectedF);
|
|
|
|
MEM_freeN(effectedE);
|
|
|
|
MEM_freeN(effectedV);
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
|
|
|
|
{
|
|
|
|
CCGFace **array;
|
|
|
|
int i, num;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
if(!*faces) {
|
2010-02-08 15:01:11 +00:00
|
|
|
array = MEM_mallocN(sizeof(*array)*ss->fMap->numEntries, "CCGSubsurf allFaces");
|
2009-11-25 12:27:21 +00:00
|
|
|
num = 0;
|
|
|
|
for (i=0; i<ss->fMap->curSize; i++) {
|
|
|
|
CCGFace *f = (CCGFace*) ss->fMap->buckets[i];
|
|
|
|
|
|
|
|
for (; f; f = f->next)
|
|
|
|
array[num++] = f;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
*faces = array;
|
|
|
|
*numFaces = num;
|
|
|
|
*freeFaces= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*freeFaces= 0;
|
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
static void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges)
|
|
|
|
{
|
|
|
|
CCGVert **arrayV;
|
|
|
|
CCGEdge **arrayE;
|
|
|
|
int numV, numE, i, j;
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
arrayV = MEM_mallocN(sizeof(*arrayV)*ss->vMap->numEntries, "CCGSubsurf arrayV");
|
|
|
|
arrayE = MEM_mallocN(sizeof(*arrayE)*ss->eMap->numEntries, "CCGSubsurf arrayV");
|
2009-11-25 12:27:21 +00:00
|
|
|
numV = numE = 0;
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numFaces; i++) {
|
|
|
|
CCGFace *f = faces[i];
|
|
|
|
f->flags |= Face_eEffected;
|
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<ss->vMap->curSize; i++) {
|
|
|
|
CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (; v; v = v->next) {
|
|
|
|
for(j=0; j<v->numFaces; j++)
|
|
|
|
if(!(v->faces[j]->flags & Face_eEffected))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(j == v->numFaces) {
|
|
|
|
arrayV[numV++] = v;
|
|
|
|
v->flags |= Vert_eEffected;
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<ss->eMap->curSize; i++) {
|
|
|
|
CCGEdge *e = (CCGEdge*) ss->eMap->buckets[i];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (; e; e = e->next) {
|
|
|
|
for(j=0; j<e->numFaces; j++)
|
|
|
|
if(!(e->faces[j]->flags & Face_eEffected))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(j == e->numFaces) {
|
|
|
|
e->flags |= Edge_eEffected;
|
|
|
|
arrayE[numE++] = e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
*verts = arrayV;
|
|
|
|
*numVerts = numV;
|
|
|
|
*edges = arrayE;
|
|
|
|
*numEdges = numE;
|
|
|
|
}
|
2006-01-10 11:36:57 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* copy face grid coordinates to other places */
|
|
|
|
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
|
|
|
|
{
|
|
|
|
int i, S, x, gridSize, cornerIdx, subdivLevels;
|
|
|
|
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
subdivLevels = ss->subdivLevels;
|
|
|
|
lvl = (lvl)? lvl: subdivLevels;
|
|
|
|
gridSize = 1 + (1<<(lvl-1));
|
|
|
|
cornerIdx = gridSize-1;
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
2006-01-10 11:36:57 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numEffectedF; i++) {
|
|
|
|
CCGFace *f = effectedF[i];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
|
|
|
|
VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=0; x<gridSize; x++)
|
|
|
|
VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=0; x<gridSize; x++) {
|
|
|
|
int eI = gridSize-1-x;
|
|
|
|
VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
|
|
|
|
VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
|
2005-04-01 02:52:55 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
if(freeF) MEM_freeN(effectedF);
|
2006-01-10 11:36:57 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-12-11 10:56:20 +00:00
|
|
|
/* copy other places to face grid coordinates */
|
|
|
|
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
|
|
|
|
{
|
|
|
|
int i, S, x, gridSize, cornerIdx, subdivLevels;
|
|
|
|
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
|
|
|
|
|
|
|
|
subdivLevels = ss->subdivLevels;
|
|
|
|
lvl = (lvl)? lvl: subdivLevels;
|
|
|
|
gridSize = 1 + (1<<(lvl-1));
|
|
|
|
cornerIdx = gridSize-1;
|
|
|
|
|
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
|
|
|
|
|
|
for (i=0; i<numEffectedF; i++) {
|
|
|
|
CCGFace *f = effectedF[i];
|
|
|
|
|
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
int prevS = (S+f->numVerts-1)%f->numVerts;
|
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
|
|
|
|
|
|
|
for (x=0; x<gridSize; x++) {
|
|
|
|
int eI = gridSize-1-x;
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x=1; x<gridSize-1; x++) {
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
|
|
|
|
}
|
|
|
|
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
if(freeF) MEM_freeN(effectedF);
|
2009-12-11 10:56:20 +00:00
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* stitch together face grids, averaging coordinates at edges
|
|
|
|
and vertices, for multires displacements */
|
|
|
|
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
|
|
|
|
{
|
|
|
|
CCGVert **effectedV;
|
|
|
|
CCGEdge **effectedE;
|
|
|
|
int numEffectedV, numEffectedE, freeF;
|
|
|
|
int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
|
|
|
|
int vertDataSize = ss->meshIFC.vertDataSize;
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
subdivLevels = ss->subdivLevels;
|
|
|
|
lvl = (lvl)? lvl: subdivLevels;
|
|
|
|
gridSize = 1 + (1<<(lvl-1));
|
|
|
|
edgeSize = 1 + (1<<lvl);
|
|
|
|
cornerIdx = gridSize-1;
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
|
|
ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
|
|
|
|
&effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* zero */
|
|
|
|
for (i=0; i<numEffectedV; i++) {
|
|
|
|
CCGVert *v = effectedV[i];
|
|
|
|
VertDataZero(VERT_getCo(v, lvl));
|
|
|
|
}
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numEffectedE; i++) {
|
|
|
|
CCGEdge *e = effectedE[i];
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=0; x<edgeSize; x++)
|
|
|
|
VertDataZero(EDGE_getCo(e, lvl, x));
|
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* add */
|
|
|
|
for (i=0; i<numEffectedF; i++) {
|
|
|
|
CCGFace *f = effectedF[i];
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataZero(FACE_getCenterData(f));
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (S=0; S<f->numVerts; S++)
|
2010-02-07 13:07:12 +00:00
|
|
|
for (x=0; x<gridSize; x++)
|
|
|
|
VertDataZero(FACE_getIECo(f, lvl, S, x));
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
int prevS = (S+f->numVerts-1)%f->numVerts;
|
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
|
2009-12-09 13:37:19 +00:00
|
|
|
if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
|
|
|
|
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=1; x<gridSize-1; x++) {
|
2010-02-07 13:07:12 +00:00
|
|
|
VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
|
|
|
|
VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=0; x<gridSize-1; x++) {
|
|
|
|
int eI = gridSize-1-x;
|
2009-12-09 13:37:19 +00:00
|
|
|
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
|
|
|
|
VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
|
|
|
|
if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
|
|
|
|
if(x != 0)
|
|
|
|
VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* average */
|
|
|
|
for (i=0; i<numEffectedV; i++) {
|
|
|
|
CCGVert *v = effectedV[i];
|
|
|
|
VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (i=0; i<numEffectedE; i++) {
|
|
|
|
CCGEdge *e = effectedE[i];
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl));
|
|
|
|
VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl));
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (x=1; x<edgeSize-1; x++)
|
|
|
|
VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces);
|
|
|
|
}
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* copy */
|
|
|
|
for (i=0; i<numEffectedF; i++) {
|
|
|
|
CCGFace *f = effectedF[i];
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (S=0; S<f->numVerts; S++)
|
2010-02-07 13:07:12 +00:00
|
|
|
for (x=1; x<gridSize-1; x++)
|
|
|
|
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (S=0; S<f->numVerts; S++) {
|
|
|
|
int prevS = (S+f->numVerts-1)%f->numVerts;
|
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
|
|
|
|
|
|
|
|
for (x=1; x<gridSize-1; x++) {
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x=0; x<gridSize-1; x++) {
|
|
|
|
int eI = gridSize-1-x;
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
|
2005-04-03 21:52:10 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f));
|
|
|
|
VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0));
|
2005-04-03 21:52:10 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2005-08-03 04:04:05 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(effectedE);
|
|
|
|
MEM_freeN(effectedV);
|
|
|
|
if(freeF) MEM_freeN(effectedF);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2005-08-03 04:04:05 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* update normals for specified faces */
|
|
|
|
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) {
|
|
|
|
CCGVert **effectedV;
|
|
|
|
CCGEdge **effectedE;
|
|
|
|
int i, numEffectedV, numEffectedE, freeF;
|
2005-08-03 04:04:05 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
|
|
ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
|
|
|
|
&effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
if (ss->calcVertNormals)
|
|
|
|
ccgSubSurf__calcVertNormals(ss,
|
|
|
|
effectedV, effectedE, effectedF,
|
|
|
|
numEffectedV, numEffectedE, numEffectedF);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
2005-06-24 05:30:41 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(effectedE);
|
|
|
|
MEM_freeN(effectedV);
|
|
|
|
if(freeF) MEM_freeN(effectedF);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* 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;
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
|
|
ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
|
|
|
|
&effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (curLvl=lvl; curLvl<subdivLevels; curLvl++) {
|
|
|
|
ccgSubSurf__calcSubdivLevel(ss,
|
|
|
|
effectedV, effectedE, effectedF,
|
|
|
|
numEffectedV, numEffectedE, numEffectedF, curLvl);
|
2005-06-23 23:44:22 +00:00
|
|
|
}
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(effectedE);
|
|
|
|
MEM_freeN(effectedV);
|
|
|
|
if(freeF) MEM_freeN(effectedF);
|
2009-11-25 12:27:21 +00:00
|
|
|
|
|
|
|
return eCCGError_None;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
#undef VERT_getCo
|
|
|
|
#undef EDGE_getCo
|
|
|
|
#undef FACE_getIECo
|
|
|
|
#undef FACE_getIFCo
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/*** External API accessor functions ***/
|
|
|
|
|
|
|
|
int ccgSubSurf_getNumVerts(CCGSubSurf *ss) {
|
|
|
|
return ss->vMap->numEntries;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getNumEdges(CCGSubSurf *ss) {
|
|
|
|
return ss->eMap->numEntries;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getNumFaces(CCGSubSurf *ss) {
|
|
|
|
return ss->fMap->numEntries;
|
|
|
|
}
|
|
|
|
|
2005-03-22 06:11:25 +00:00
|
|
|
CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) {
|
|
|
|
return (CCGVert*) _ehash_lookup(ss->vMap, v);
|
|
|
|
}
|
|
|
|
CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) {
|
|
|
|
return (CCGEdge*) _ehash_lookup(ss->eMap, e);
|
|
|
|
}
|
|
|
|
CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) {
|
|
|
|
return (CCGFace*) _ehash_lookup(ss->fMap, f);
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
int ccgSubSurf_getSubdivisionLevels(CCGSubSurf *ss) {
|
|
|
|
return ss->subdivLevels;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getEdgeSize(CCGSubSurf *ss) {
|
|
|
|
return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getEdgeLevelSize(CCGSubSurf *ss, int level) {
|
|
|
|
if (level<1 || level>ss->subdivLevels) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 1 + (1<<level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getGridSize(CCGSubSurf *ss) {
|
|
|
|
return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) {
|
|
|
|
if (level<1 || level>ss->subdivLevels) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 1 + (1<<(level-1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Vert accessors */
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->vHDL;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) {
|
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getVertUserData(ss, v);
|
|
|
|
return ss->currentAge - *((int*) &userData[ss->vertUserAgeOffset]);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) {
|
|
|
|
return VERT_getLevelData(v) + ss->meshIFC.vertDataSize*(ss->subdivLevels+1);
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
int ccgSubSurf_getVertNumFaces(CCGVert *v) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->numFaces;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (index<0 || index>=v->numFaces) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return v->faces[index];
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
int ccgSubSurf_getVertNumEdges(CCGVert *v) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->numEdges;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (index<0 || index>=v->numEdges) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return v->edges[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) {
|
|
|
|
return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) {
|
|
|
|
if (level<0 || level>ss->subdivLevels) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return _vert_getCo(v, level, ss->meshIFC.vertDataSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Edge accessors */
|
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->eHDL;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) {
|
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
|
|
|
|
return ss->currentAge - *((int*) &userData[ss->edgeUserAgeOffset]);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) {
|
|
|
|
return EDGE_getLevelData(e) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1);
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
int ccgSubSurf_getEdgeNumFaces(CCGEdge *e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->numFaces;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (index<0 || index>=e->numFaces) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return e->faces[index];
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->v0;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->v1;
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) {
|
|
|
|
return ccgSubSurf_getEdgeData(ss, e, 0);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) {
|
|
|
|
return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) {
|
|
|
|
if (level<0 || level>ss->subdivLevels) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
float ccgSubSurf_getEdgeCrease(CCGEdge *e) {
|
2006-01-10 11:36:57 +00:00
|
|
|
return e->crease;
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
/* Face accessors */
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGSubSurf *UNUSED(ss), CCGFace *f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return f->fHDL;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) {
|
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getFaceUserData(ss, f);
|
|
|
|
return ss->currentAge - *((int*) &userData[ss->faceUserAgeOffset]);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) {
|
|
|
|
int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
|
|
|
|
return FACE_getCenterData(f) + ss->meshIFC.vertDataSize *(1 + f->numVerts*maxGridSize + f->numVerts*maxGridSize*maxGridSize);
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
int ccgSubSurf_getFaceNumVerts(CCGFace *f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return f->numVerts;
|
|
|
|
}
|
2010-10-17 06:38:56 +00:00
|
|
|
CCGVert *ccgSubSurf_getFaceVert(CCGSubSurf *UNUSED(ss), CCGFace *f, int index) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (index<0 || index>=f->numVerts) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return FACE_getVerts(f)[index];
|
|
|
|
}
|
|
|
|
}
|
2010-10-17 06:38:56 +00:00
|
|
|
CCGEdge *ccgSubSurf_getFaceEdge(CCGSubSurf *UNUSED(ss), CCGFace *f, int index) {
|
2005-03-21 01:34:27 +00:00
|
|
|
if (index<0 || index>=f->numVerts) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return FACE_getEdges(f)[index];
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e) {
|
2005-08-18 11:31:20 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<f->numVerts; i++)
|
|
|
|
if (FACE_getEdges(f)[i]==e)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2008-09-29 17:08:11 +00:00
|
|
|
void *ccgSubSurf_getFaceCenterData(CCGFace *f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return FACE_getCenterData(f);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
|
|
|
|
return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) {
|
|
|
|
return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
|
|
|
|
}
|
|
|
|
void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
|
|
|
|
return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** External API iterator functions ***/
|
|
|
|
|
|
|
|
CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) {
|
|
|
|
return (CCGVertIterator*) _ehashIterator_new(ss->vMap);
|
|
|
|
}
|
|
|
|
CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) {
|
|
|
|
return (CCGEdgeIterator*) _ehashIterator_new(ss->eMap);
|
|
|
|
}
|
|
|
|
CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) {
|
|
|
|
return (CCGFaceIterator*) _ehashIterator_new(ss->fMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) {
|
|
|
|
return (CCGVert*) _ehashIterator_getCurrent((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
int ccgVertIterator_isStopped(CCGVertIterator *vi) {
|
|
|
|
return _ehashIterator_isStopped((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgVertIterator_next(CCGVertIterator *vi) {
|
|
|
|
_ehashIterator_next((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgVertIterator_free(CCGVertIterator *vi) {
|
|
|
|
_ehashIterator_free((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) {
|
|
|
|
return (CCGEdge*) _ehashIterator_getCurrent((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) {
|
|
|
|
return _ehashIterator_isStopped((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgEdgeIterator_next(CCGEdgeIterator *vi) {
|
|
|
|
_ehashIterator_next((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgEdgeIterator_free(CCGEdgeIterator *vi) {
|
|
|
|
_ehashIterator_free((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
|
|
|
|
CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) {
|
|
|
|
return (CCGFace*) _ehashIterator_getCurrent((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
int ccgFaceIterator_isStopped(CCGFaceIterator *vi) {
|
|
|
|
return _ehashIterator_isStopped((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgFaceIterator_next(CCGFaceIterator *vi) {
|
|
|
|
_ehashIterator_next((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
void ccgFaceIterator_free(CCGFaceIterator *vi) {
|
|
|
|
_ehashIterator_free((EHashIterator*) vi);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** Extern API final vert/edge/face interface ***/
|
|
|
|
|
|
|
|
int ccgSubSurf_getNumFinalVerts(CCGSubSurf *ss) {
|
|
|
|
int edgeSize = 1 + (1<<ss->subdivLevels);
|
|
|
|
int gridSize = 1 + (1<<(ss->subdivLevels-1));
|
|
|
|
int numFinalVerts = ss->vMap->numEntries + ss->eMap->numEntries*(edgeSize-2) + ss->fMap->numEntries + ss->numGrids*((gridSize-2) + ((gridSize-2)*(gridSize-2)));
|
|
|
|
return numFinalVerts;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getNumFinalEdges(CCGSubSurf *ss) {
|
|
|
|
int edgeSize = 1 + (1<<ss->subdivLevels);
|
|
|
|
int gridSize = 1 + (1<<(ss->subdivLevels-1));
|
|
|
|
int numFinalEdges = ss->eMap->numEntries*(edgeSize-1) + ss->numGrids*((gridSize-1) + 2*((gridSize-2)*(gridSize-1)));
|
|
|
|
return numFinalEdges;
|
|
|
|
}
|
|
|
|
int ccgSubSurf_getNumFinalFaces(CCGSubSurf *ss) {
|
|
|
|
int gridSize = 1 + (1<<(ss->subdivLevels-1));
|
|
|
|
int numFinalFaces = ss->numGrids*((gridSize-1)*(gridSize-1));
|
|
|
|
return numFinalFaces;
|
|
|
|
}
|