Files
test/source/blender/blenkernel/intern/CCGSubSurf.cc
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

1581 lines
43 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* 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.hh"
#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 *user_data;
v->vHDL = vHDL;
v->edges = nullptr;
v->faces = nullptr;
v->numEdges = v->numFaces = 0;
v->flags = 0;
user_data = static_cast<byte *>(ccgSubSurf_getVertUserData(ss, v));
memset(user_data, 0, ss->meshIFC.vertUserSize);
if (ss->useAgeCounts) {
*((int *)&user_data[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 *user_data;
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);
user_data = static_cast<byte *>(ccgSubSurf_getEdgeUserData(ss, e));
memset(user_data, 0, ss->meshIFC.edgeUserSize);
if (ss->useAgeCounts) {
*((int *)&user_data[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 *user_data;
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);
}
user_data = static_cast<byte *>(ccgSubSurf_getFaceUserData(ss, f));
memset(user_data, 0, ss->meshIFC.faceUserSize);
if (ss->useAgeCounts) {
*((int *)&user_data[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 *user_data = static_cast<byte *>(ccgSubSurf_getVertUserData(ss, v));
return ss->currentAge - *((int *)&user_data[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 *user_data = static_cast<byte *>(ccgSubSurf_getEdgeUserData(ss, e));
return ss->currentAge - *((int *)&user_data[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 *user_data = static_cast<byte *>(ccgSubSurf_getFaceUserData(ss, f));
return ss->currentAge - *((int *)&user_data[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));
}