tornavis/source/blender/blenkernel/intern/CCGSubSurf.cc

1581 lines
43 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "BLI_sys_types.h" /* for intptr_t support */
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h" /* for BLI_assert */
#include "BKE_ccg.h"
#include "BKE_subsurf.h"
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
/***/
int BKE_ccg_gridsize(int level)
{
return ccg_gridsize(level);
}
int BKE_ccg_factor(int low_level, int high_level)
{
BLI_assert(low_level > 0 && high_level > 0);
BLI_assert(low_level <= high_level);
return 1 << (high_level - low_level);
}
/***/
static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss)
{
int num_vert_data = ss->subdivLevels + 1;
CCGVert *v = static_cast<CCGVert *>(CCGSUBSURF_alloc(
ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * num_vert_data + ss->meshIFC.vertUserSize));
byte *userData;
v->vHDL = vHDL;
v->edges = nullptr;
v->faces = nullptr;
v->numEdges = v->numFaces = 0;
v->flags = 0;
userData = static_cast<byte *>(ccgSubSurf_getVertUserData(ss, v));
memset(userData, 0, ss->meshIFC.vertUserSize);
if (ss->useAgeCounts) {
*((int *)&userData[ss->vertUserAgeOffset]) = ss->currentAge;
}
return v;
}
static void _vert_remEdge(CCGVert *v, CCGEdge *e)
{
for (int i = 0; i < v->numEdges; i++) {
if (v->edges[i] == e) {
v->edges[i] = v->edges[--v->numEdges];
break;
}
}
}
static void _vert_remFace(CCGVert *v, CCGFace *f)
{
for (int 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 = static_cast<CCGEdge **>(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 = static_cast<CCGFace **>(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(const CCGVert *v, const CCGVert *vQ)
{
for (int 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;
}
}
return nullptr;
}
static void _vert_free(CCGVert *v, CCGSubSurf *ss)
{
if (v->edges) {
CCGSUBSURF_free(ss, v->edges);
}
if (v->faces) {
CCGSUBSURF_free(ss, v->faces);
}
CCGSUBSURF_free(ss, v);
}
/***/
static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss)
{
int num_edge_data = ccg_edgebase(ss->subdivLevels + 1);
CCGEdge *e = static_cast<CCGEdge *>(CCGSUBSURF_alloc(
ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize * num_edge_data + ss->meshIFC.edgeUserSize));
byte *userData;
e->eHDL = eHDL;
e->v0 = v0;
e->v1 = v1;
e->crease = crease;
e->faces = nullptr;
e->numFaces = 0;
e->flags = 0;
_vert_addEdge(v0, e, ss);
_vert_addEdge(v1, e, ss);
userData = static_cast<byte *>(ccgSubSurf_getEdgeUserData(ss, e));
memset(userData, 0, ss->meshIFC.edgeUserSize);
if (ss->useAgeCounts) {
*((int *)&userData[ss->edgeUserAgeOffset]) = ss->currentAge;
}
return e;
}
static void _edge_remFace(CCGEdge *e, CCGFace *f)
{
for (int i = 0; i < e->numFaces; i++) {
if (e->faces[i] == f) {
e->faces[i] = e->faces[--e->numFaces];
break;
}
}
}
static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss)
{
e->faces = static_cast<CCGFace **>(CCGSUBSURF_realloc(
ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces)));
e->faces[e->numFaces++] = f;
}
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize)
{
int levelBase = ccg_edgebase(lvl);
if (v == e->v0) {
return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
}
return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
}
static void _edge_free(CCGEdge *e, CCGSubSurf *ss)
{
if (e->faces) {
CCGSUBSURF_free(ss, e->faces);
}
CCGSUBSURF_free(ss, e);
}
static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss)
{
_vert_remEdge(e->v0, e);
_vert_remEdge(e->v1, e);
e->v0->flags |= Vert_eEffected;
e->v1->flags |= Vert_eEffected;
_edge_free(e, ss);
}
static CCGFace *_face_new(
CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss)
{
int maxGridSize = ccg_gridsize(ss->subdivLevels);
int num_face_data = (numVerts * maxGridSize + numVerts * maxGridSize * maxGridSize + 1);
CCGFace *f = static_cast<CCGFace *>(CCGSUBSURF_alloc(
ss,
sizeof(CCGFace) + sizeof(CCGVert *) * numVerts + sizeof(CCGEdge *) * numVerts +
ss->meshIFC.vertDataSize * num_face_data + ss->meshIFC.faceUserSize));
byte *userData;
f->numVerts = numVerts;
BLI_assert(numVerts > 2);
f->fHDL = fHDL;
f->flags = 0;
for (int 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 = static_cast<byte *>(ccgSubSurf_getFaceUserData(ss, f));
memset(userData, 0, ss->meshIFC.faceUserSize);
if (ss->useAgeCounts) {
*((int *)&userData[ss->faceUserAgeOffset]) = ss->currentAge;
}
return f;
}
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++) {
_vert_remFace(FACE_getVerts(f)[j], f);
_edge_remFace(FACE_getEdges(f)[j], f);
FACE_getVerts(f)[j]->flags |= Vert_eEffected;
}
_face_free(f, ss);
}
/***/
CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
int subdivLevels,
CCGAllocatorIFC *allocatorIFC,
CCGAllocatorHDL allocator)
{
if (!allocatorIFC) {
allocatorIFC = ccg_getStandardAllocatorIFC();
allocator = nullptr;
}
if (subdivLevels < 1) {
return nullptr;
}
CCGSubSurf *ss = static_cast<CCGSubSurf *>(allocatorIFC->alloc(allocator, sizeof(*ss)));
ss->allocatorIFC = *allocatorIFC;
ss->allocator = allocator;
ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->meshIFC = *ifc;
ss->subdivLevels = subdivLevels;
ss->numGrids = 0;
ss->allowEdgeCreation = 0;
ss->defaultCreaseValue = 0;
ss->defaultEdgeUserData = nullptr;
ss->useAgeCounts = 0;
ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
ss->calcVertNormals = 0;
ss->normalDataOffset = 0;
ss->allocMask = 0;
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 = nullptr;
ss->lenTempArrays = 0;
ss->tempVerts = nullptr;
ss->tempEdges = nullptr;
return ss;
}
void ccgSubSurf_free(CCGSubSurf *ss)
{
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
CCGAllocatorHDL allocator = ss->allocator;
if (ss->syncState) {
ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss);
ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_free, ss);
ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss);
MEM_freeN(ss->tempVerts);
MEM_freeN(ss->tempEdges);
}
CCGSUBSURF_free(ss, ss->r);
CCGSUBSURF_free(ss, ss->q);
if (ss->defaultEdgeUserData) {
CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
}
ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss);
ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss);
ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss);
CCGSUBSURF_free(ss, ss);
if (allocatorIFC.release) {
allocatorIFC.release(allocator);
}
}
CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss,
int allowEdgeCreation,
float defaultCreaseValue,
void *defaultUserData)
{
if (ss->defaultEdgeUserData) {
CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
}
ss->allowEdgeCreation = !!allowEdgeCreation;
ss->defaultCreaseValue = defaultCreaseValue;
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);
}
return eCCGError_None;
}
void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss,
int *allowEdgeCreation_r,
float *defaultCreaseValue_r,
void *defaultUserData_r)
{
if (allowEdgeCreation_r) {
*allowEdgeCreation_r = ss->allowEdgeCreation;
}
if (ss->allowEdgeCreation) {
if (defaultCreaseValue_r) {
*defaultCreaseValue_r = ss->defaultCreaseValue;
}
if (defaultUserData_r) {
memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
}
}
}
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels)
{
if (subdivisionLevels <= 0) {
return eCCGError_InvalidValue;
}
if (subdivisionLevels != ss->subdivLevels) {
ss->numGrids = 0;
ss->subdivLevels = subdivisionLevels;
ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss);
ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss);
ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss);
ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
}
return eCCGError_None;
}
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;
}
}
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;
}
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;
}
CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset)
{
if (useVertNormals) {
if (normalDataOffset < 0 || normalDataOffset + 12 > ss->meshIFC.vertDataSize) {
return eCCGError_InvalidValue;
}
ss->calcVertNormals = 1;
ss->normalDataOffset = normalDataOffset;
}
else {
ss->calcVertNormals = 0;
ss->normalDataOffset = 0;
}
return eCCGError_None;
}
void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset)
{
ss->allocMask = allocMask;
ss->maskDataOffset = maskOffset;
}
void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers)
{
ss->meshIFC.numLayers = numLayers;
}
/***/
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;
ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
ss->numGrids = 0;
ss->lenTempArrays = 12;
ss->tempVerts = static_cast<CCGVert **>(
MEM_mallocN(sizeof(*ss->tempVerts) * ss->lenTempArrays, "CCGSubsurf tempVerts"));
ss->tempEdges = static_cast<CCGEdge **>(
MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges"));
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;
}
void **prevp;
CCGVert *v = static_cast<CCGVert *>(ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp));
if (!v || v->numFaces || v->numEdges) {
return eCCGError_InvalidValue;
}
*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;
}
void **prevp;
CCGEdge *e = static_cast<CCGEdge *>(ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp));
if (!e || e->numFaces) {
return eCCGError_InvalidValue;
}
*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;
}
void **prevp;
CCGFace *f = static_cast<CCGFace *>(ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp));
if (!f) {
return eCCGError_InvalidValue;
}
*prevp = f->next;
_face_unlinkMarkAndFree(f, ss);
return eCCGError_None;
}
CCGError ccgSubSurf_syncVert(
CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r)
{
void **prevp;
CCGVert *v = nullptr;
short seamflag = (seam) ? Vert_eSeam : 0;
if (ss->syncState == eSyncState_Partial) {
v = static_cast<CCGVert *>(ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp));
if (!v) {
v = _vert_new(vHDL, ss);
VertDataCopy(static_cast<float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
static_cast<const float *>(vertData),
ss);
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
v->flags = Vert_eEffected | seamflag;
}
else if (!VertDataEqual(
static_cast<const float *>(vertData),
static_cast<const float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
ss) ||
((v->flags & Vert_eSeam) != seamflag))
{
int i, j;
VertDataCopy(static_cast<float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
static_cast<const float *>(vertData),
ss);
v->flags = Vert_eEffected | seamflag;
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 = static_cast<CCGVert *>(ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp));
if (!v) {
v = _vert_new(vHDL, ss);
VertDataCopy(static_cast<float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
static_cast<const float *>(vertData),
ss);
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
v->flags = Vert_eEffected | seamflag;
}
else if (!VertDataEqual(
static_cast<const float *>(vertData),
static_cast<const float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
ss) ||
((v->flags & Vert_eSeam) != seamflag))
{
*prevp = v->next;
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
VertDataCopy(static_cast<float *>(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)),
static_cast<const float *>(vertData),
ss);
v->flags = Vert_eEffected | Vert_eChanged | seamflag;
}
else {
*prevp = v->next;
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
v->flags = 0;
}
}
if (v_r) {
*v_r = v;
}
return eCCGError_None;
}
CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss,
CCGEdgeHDL eHDL,
CCGVertHDL e_vHDL0,
CCGVertHDL e_vHDL1,
float crease,
CCGEdge **e_r)
{
void **prevp;
CCGEdge *e = nullptr, *eNew;
if (ss->syncState == eSyncState_Partial) {
e = static_cast<CCGEdge *>(ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp));
if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) {
CCGVert *v0 = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, e_vHDL0));
CCGVert *v1 = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, e_vHDL1));
eNew = _edge_new(eHDL, v0, v1, crease, ss);
if (e) {
*prevp = eNew;
eNew->next = e->next;
_edge_unlinkMarkAndFree(e, ss);
}
else {
ccg_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 = static_cast<CCGEdge *>(ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp));
if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) {
CCGVert *v0 = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, e_vHDL0));
CCGVert *v1 = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, e_vHDL1));
e = _edge_new(eHDL, v0, v1, crease, ss);
ccg_ehash_insert(ss->eMap, (EHEntry *)e);
e->v0->flags |= Vert_eEffected;
e->v1->flags |= Vert_eEffected;
}
else {
*prevp = e->next;
ccg_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;
}
}
}
if (e_r) {
*e_r = e;
}
return eCCGError_None;
}
CCGError ccgSubSurf_syncFace(
CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r)
{
void **prevp;
CCGFace *f = nullptr, *fNew;
int j, k, topologyChanged = 0;
if (UNLIKELY(numVerts > ss->lenTempArrays)) {
ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts;
ss->tempVerts = static_cast<CCGVert **>(
MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays));
ss->tempEdges = static_cast<CCGEdge **>(
MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays));
}
if (ss->syncState == eSyncState_Partial) {
f = static_cast<CCGFace *>(ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp));
for (k = 0; k < numVerts; k++) {
ss->tempVerts[k] = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, vHDLs[k]));
}
for (k = 0; k < numVerts; k++) {
ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
}
if (f) {
if (f->numVerts != numVerts ||
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 ||
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0)
{
topologyChanged = 1;
}
}
if (!f || topologyChanged) {
fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
if (f) {
ss->numGrids += numVerts - f->numVerts;
*prevp = fNew;
fNew->next = f->next;
_face_unlinkMarkAndFree(f, ss);
}
else {
ss->numGrids += numVerts;
ccg_ehash_insert(ss->fMap, (EHEntry *)fNew);
}
for (k = 0; k < numVerts; k++) {
FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
}
}
}
else {
if (ELEM(ss->syncState, eSyncState_Vert, eSyncState_Edge)) {
ss->syncState = eSyncState_Face;
}
else if (ss->syncState != eSyncState_Face) {
return eCCGError_InvalidSyncState;
}
f = static_cast<CCGFace *>(ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp));
for (k = 0; k < numVerts; k++) {
ss->tempVerts[k] = static_cast<CCGVert *>(ccg_ehash_lookup(ss->vMap, vHDLs[k]));
if (!ss->tempVerts[k]) {
return eCCGError_InvalidValue;
}
}
for (k = 0; k < numVerts; k++) {
ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
if (!ss->tempEdges[k]) {
if (ss->allowEdgeCreation) {
CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL)-1,
ss->tempVerts[k],
ss->tempVerts[(k + 1) % numVerts],
ss->defaultCreaseValue,
ss);
ccg_ehash_insert(ss->eMap, (EHEntry *)e);
e->v0->flags |= Vert_eEffected;
e->v1->flags |= Vert_eEffected;
if (ss->meshIFC.edgeUserSize) {
memcpy(ccgSubSurf_getEdgeUserData(ss, e),
ss->defaultEdgeUserData,
ss->meshIFC.edgeUserSize);
}
}
else {
return eCCGError_InvalidValue;
}
}
}
if (f) {
if (f->numVerts != numVerts ||
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 ||
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0)
{
topologyChanged = 1;
}
}
if (!f || topologyChanged) {
f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
ccg_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;
ccg_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;
}
}
}
}
if (f_r) {
*f_r = f;
}
return eCCGError_None;
}
static void ccgSubSurf__sync(CCGSubSurf *ss)
{
ccgSubSurf__sync_legacy(ss);
}
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
{
if (ss->syncState == eSyncState_Partial) {
ss->syncState = eSyncState_None;
ccgSubSurf__sync(ss);
}
else if (ss->syncState) {
ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_unlinkMarkAndFree, ss);
ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_unlinkMarkAndFree, ss);
ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss);
MEM_freeN(ss->tempEdges);
MEM_freeN(ss->tempVerts);
ss->lenTempArrays = 0;
ss->oldFMap = ss->oldEMap = ss->oldVMap = nullptr;
ss->tempVerts = nullptr;
ss->tempEdges = nullptr;
ss->syncState = eSyncState_None;
ccgSubSurf__sync(ss);
}
else {
return eCCGError_InvalidSyncState;
}
return eCCGError_None;
}
void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
{
CCGFace **array;
int i, num;
if (*faces == nullptr) {
array = static_cast<CCGFace **>(
MEM_mallocN(sizeof(*array) * ss->fMap->numEntries, "CCGSubsurf allFaces"));
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;
}
}
*faces = array;
*numFaces = num;
*freeFaces = 1;
}
else {
*freeFaces = 0;
}
}
void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
CCGFace **faces,
int numFaces,
CCGVert ***verts,
int *numVerts,
CCGEdge ***edges,
int *numEdges)
{
CCGVert **arrayV;
CCGEdge **arrayE;
int numV, numE, i, j;
arrayV = static_cast<CCGVert **>(
MEM_mallocN(sizeof(*arrayV) * ss->vMap->numEntries, "CCGSubsurf arrayV"));
arrayE = static_cast<CCGEdge **>(
MEM_mallocN(sizeof(*arrayE) * ss->eMap->numEntries, "CCGSubsurf arrayV"));
numV = numE = 0;
for (i = 0; i < numFaces; i++) {
CCGFace *f = faces[i];
f->flags |= Face_eEffected;
}
for (i = 0; i < ss->vMap->curSize; i++) {
CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
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;
}
}
}
for (i = 0; i < ss->eMap->curSize; i++) {
CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i];
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;
}
}
}
*verts = arrayV;
*numVerts = numV;
*edges = arrayE;
*numEdges = numE;
}
CCGError ccgSubSurf_updateFromFaces(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 = ccg_gridsize(lvl);
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++) {
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
VertDataCopy((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
VertDataCopy(
VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss);
for (x = 0; x < gridSize; x++) {
VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
}
for (x = 0; x < gridSize; x++) {
int eI = gridSize - 1 - x;
VertDataCopy(
static_cast<float *>(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
FACE_getIFCo(f, lvl, S, cornerIdx, x),
ss);
VertDataCopy(static_cast<float *>(
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
FACE_getIFCo(f, lvl, S, x, cornerIdx),
ss);
}
}
}
if (freeF) {
MEM_freeN(effectedF);
}
return eCCGError_None;
}
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 = ccg_gridsize(lvl);
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),
static_cast<const float *>(
_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
ss);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
static_cast<const float *>(
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
ss);
}
for (x = 1; x < gridSize - 1; x++) {
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
}
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
VertDataCopy(
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
}
}
if (freeF) {
MEM_freeN(effectedF);
}
return eCCGError_None;
}
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;
subdivLevels = ss->subdivLevels;
lvl = (lvl) ? lvl : subdivLevels;
gridSize = ccg_gridsize(lvl);
edgeSize = ccg_edgesize(lvl);
cornerIdx = gridSize - 1;
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
ccgSubSurf__effectedFaceNeighbors(
ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
/* zero */
for (i = 0; i < numEffectedV; i++) {
CCGVert *v = effectedV[i];
if (v->numFaces) {
VertDataZero(VERT_getCo(v, lvl), ss);
}
}
for (i = 0; i < numEffectedE; i++) {
CCGEdge *e = effectedE[i];
if (e->numFaces) {
for (x = 0; x < edgeSize; x++) {
VertDataZero(EDGE_getCo(e, lvl, x), ss);
}
}
}
/* add */
for (i = 0; i < numEffectedF; i++) {
CCGFace *f = effectedF[i];
VertDataZero((float *)FACE_getCenterData(f), ss);
for (S = 0; S < f->numVerts; S++) {
for (x = 0; x < gridSize; x++) {
VertDataZero(FACE_getIECo(f, lvl, S, x), ss);
}
}
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];
VertDataAdd((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl),
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx),
ss);
}
for (x = 1; x < gridSize - 1; x++) {
VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), ss);
}
for (x = 0; x < gridSize - 1; x++) {
int eI = gridSize - 1 - x;
if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
VertDataAdd(
static_cast<float *>(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
FACE_getIFCo(f, lvl, S, cornerIdx, x),
ss);
}
if (FACE_getEdges(f)[prevS]->flags & Edge_eEffected) {
if (x != 0) {
VertDataAdd(static_cast<float *>(
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
FACE_getIFCo(f, lvl, S, x, cornerIdx),
ss);
}
}
}
}
}
/* average */
for (i = 0; i < numEffectedV; i++) {
CCGVert *v = effectedV[i];
if (v->numFaces) {
VertDataMulN(VERT_getCo(v, lvl), 1.0f / v->numFaces, ss);
}
}
for (i = 0; i < numEffectedE; i++) {
CCGEdge *e = effectedE[i];
VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), ss);
VertDataCopy(EDGE_getCo(e, lvl, edgeSize - 1), VERT_getCo(e->v1, lvl), ss);
if (e->numFaces) {
for (x = 1; x < edgeSize - 1; x++) {
VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f / e->numFaces, ss);
}
}
}
/* copy */
for (i = 0; i < numEffectedF; i++) {
CCGFace *f = effectedF[i];
VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
for (S = 0; S < f->numVerts; S++) {
for (x = 1; x < gridSize - 1; x++) {
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, ss);
}
}
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];
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
VertDataCopy(
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
for (x = 1; x < gridSize - 1; x++) {
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
}
for (x = 0; x < gridSize - 1; x++) {
int eI = gridSize - 1 - x;
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x),
static_cast<const float *>(
_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
ss);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
static_cast<const float *>(
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)),
ss);
}
VertDataCopy(FACE_getIECo(f, lvl, S, 0), (float *)FACE_getCenterData(f), ss);
VertDataCopy(
FACE_getIECo(f, lvl, S, gridSize - 1), FACE_getIFCo(f, lvl, S, gridSize - 1, 0), ss);
}
}
for (i = 0; i < numEffectedV; i++) {
effectedV[i]->flags = 0;
}
for (i = 0; i < numEffectedE; i++) {
effectedE[i]->flags = 0;
}
for (i = 0; i < numEffectedF; i++) {
effectedF[i]->flags = 0;
}
MEM_freeN(effectedE);
MEM_freeN(effectedV);
if (freeF) {
MEM_freeN(effectedF);
}
return eCCGError_None;
}
/*** External API accessor functions ***/
int ccgSubSurf_getNumVerts(const CCGSubSurf *ss)
{
return ss->vMap->numEntries;
}
int ccgSubSurf_getNumEdges(const CCGSubSurf *ss)
{
return ss->eMap->numEntries;
}
int ccgSubSurf_getNumFaces(const CCGSubSurf *ss)
{
return ss->fMap->numEntries;
}
CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v)
{
return (CCGVert *)ccg_ehash_lookup(ss->vMap, v);
}
CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e)
{
return (CCGEdge *)ccg_ehash_lookup(ss->eMap, e);
}
CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f)
{
return (CCGFace *)ccg_ehash_lookup(ss->fMap, f);
}
int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss)
{
return ss->subdivLevels;
}
int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss)
{
return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
}
int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level)
{
if (level < 1 || level > ss->subdivLevels) {
return -1;
}
return ccg_edgesize(level);
}
int ccgSubSurf_getGridSize(const CCGSubSurf *ss)
{
return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
}
int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level)
{
if (level < 1 || level > ss->subdivLevels) {
return -1;
}
return ccg_gridsize(level);
}
int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss)
{
return ss->meshIFC.simpleSubdiv;
}
/* Vert accessors */
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v)
{
return v->vHDL;
}
int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v)
{
if (ss->useAgeCounts) {
byte *userData = static_cast<byte *>(ccgSubSurf_getVertUserData(ss, v));
return ss->currentAge - *((int *)&userData[ss->vertUserAgeOffset]);
}
return 0;
}
void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v)
{
return VERT_getLevelData(v) + ss->meshIFC.vertDataSize * (ss->subdivLevels + 1);
}
int ccgSubSurf_getVertNumFaces(CCGVert *v)
{
return v->numFaces;
}
CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index)
{
if (index < 0 || index >= v->numFaces) {
return nullptr;
}
return v->faces[index];
}
int ccgSubSurf_getVertNumEdges(CCGVert *v)
{
return v->numEdges;
}
CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index)
{
if (index < 0 || index >= v->numEdges) {
return nullptr;
}
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 nullptr;
}
return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize);
}
/* Edge accessors */
CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e)
{
return e->eHDL;
}
int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e)
{
if (ss->useAgeCounts) {
byte *userData = static_cast<byte *>(ccgSubSurf_getEdgeUserData(ss, e));
return ss->currentAge - *((int *)&userData[ss->edgeUserAgeOffset]);
}
return 0;
}
void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e)
{
return (EDGE_getLevelData(e) + ss->meshIFC.vertDataSize * ccg_edgebase(ss->subdivLevels + 1));
}
int ccgSubSurf_getEdgeNumFaces(CCGEdge *e)
{
return e->numFaces;
}
CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index)
{
if (index < 0 || index >= e->numFaces) {
return nullptr;
}
return e->faces[index];
}
CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e)
{
return e->v0;
}
CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e)
{
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 nullptr;
}
return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
}
float ccgSubSurf_getEdgeCrease(CCGEdge *e)
{
return e->crease;
}
/* Face accessors */
CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f)
{
return f->fHDL;
}
int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f)
{
if (ss->useAgeCounts) {
byte *userData = static_cast<byte *>(ccgSubSurf_getFaceUserData(ss, f));
return ss->currentAge - *((int *)&userData[ss->faceUserAgeOffset]);
}
return 0;
}
void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f)
{
int maxGridSize = ccg_gridsize(ss->subdivLevels);
return FACE_getCenterData(f) +
ss->meshIFC.vertDataSize *
(1 + f->numVerts * maxGridSize + f->numVerts * maxGridSize * maxGridSize);
}
int ccgSubSurf_getFaceNumVerts(CCGFace *f)
{
return f->numVerts;
}
CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index)
{
if (index < 0 || index >= f->numVerts) {
return nullptr;
}
return FACE_getVerts(f)[index];
}
CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index)
{
if (index < 0 || index >= f->numVerts) {
return nullptr;
}
return FACE_getEdges(f)[index];
}
int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e)
{
for (int i = 0; i < f->numVerts; i++) {
if (FACE_getEdges(f)[i] == e) {
return i;
}
}
return -1;
}
void *ccgSubSurf_getFaceCenterData(CCGFace *f)
{
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 ccg_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 ccg_face_getIFCo(
f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
}
/*** External API iterator functions ***/
void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter)
{
ccg_ehashIterator_init(ss->vMap, viter);
}
void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter)
{
ccg_ehashIterator_init(ss->eMap, eiter);
}
void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter)
{
ccg_ehashIterator_init(ss->fMap, fiter);
}
CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi)
{
return (CCGVert *)ccg_ehashIterator_getCurrent((EHashIterator *)vi);
}
int ccgVertIterator_isStopped(CCGVertIterator *vi)
{
return ccg_ehashIterator_isStopped((EHashIterator *)vi);
}
void ccgVertIterator_next(CCGVertIterator *vi)
{
ccg_ehashIterator_next((EHashIterator *)vi);
}
CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *ei)
{
return (CCGEdge *)ccg_ehashIterator_getCurrent((EHashIterator *)ei);
}
int ccgEdgeIterator_isStopped(CCGEdgeIterator *ei)
{
return ccg_ehashIterator_isStopped((EHashIterator *)ei);
}
void ccgEdgeIterator_next(CCGEdgeIterator *ei)
{
ccg_ehashIterator_next((EHashIterator *)ei);
}
CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi)
{
return (CCGFace *)ccg_ehashIterator_getCurrent((EHashIterator *)fi);
}
int ccgFaceIterator_isStopped(CCGFaceIterator *fi)
{
return ccg_ehashIterator_isStopped((EHashIterator *)fi);
}
void ccgFaceIterator_next(CCGFaceIterator *fi)
{
ccg_ehashIterator_next((EHashIterator *)fi);
}
/*** Extern API final vert/edge/face interface ***/
int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss)
{
int edgeSize = ccg_edgesize(ss->subdivLevels);
int gridSize = ccg_gridsize(ss->subdivLevels);
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(const CCGSubSurf *ss)
{
int edgeSize = ccg_edgesize(ss->subdivLevels);
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
return numFinalEdges;
}
int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss)
{
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
return numFinalFaces;
}
/***/
void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level)
{
key->level = level;
key->elem_size = ss->meshIFC.vertDataSize;
key->has_normals = ss->calcVertNormals;
/* if normals are present, always the last three floats of an
* element */
if (key->has_normals) {
key->normal_offset = key->elem_size - sizeof(float[3]);
}
else {
key->normal_offset = -1;
}
key->grid_size = ccgSubSurf_getGridLevelSize(ss, level);
key->grid_area = key->grid_size * key->grid_size;
key->grid_bytes = key->elem_size * key->grid_area;
key->has_mask = ss->allocMask;
if (key->has_mask) {
key->mask_offset = ss->maskDataOffset;
}
else {
key->mask_offset = -1;
}
}
void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss)
{
CCG_key(key, ss, ccgSubSurf_getSubdivisionLevels(ss));
}