2013-07-02 09:47:22 +00:00
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
2011-10-10 09:38:02 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup bke
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <math.h>
|
2005-03-21 01:34:27 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2013-05-28 19:35:26 +00:00
|
|
|
#include "BLI_sys_types.h" /* for intptr_t support */
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "MEM_guardedalloc.h"
|
2008-08-17 17:08:00 +00:00
|
|
|
|
2012-02-23 07:21:33 +00:00
|
|
|
#include "BLI_utildefines.h" /* for BLI_assert */
|
|
|
|
|
2013-04-05 17:56:54 +00:00
|
|
|
#include "BKE_ccg.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_subsurf.h"
|
2013-04-05 17:56:54 +00:00
|
|
|
#include "CCGSubSurf.h"
|
2015-07-20 15:05:16 +02:00
|
|
|
#include "CCGSubSurf_intern.h"
|
2013-04-05 17:56:54 +00:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/***/
|
|
|
|
|
2013-10-01 09:17:35 +00:00
|
|
|
int BKE_ccg_gridsize(int level)
|
|
|
|
{
|
|
|
|
return ccg_gridsize(level);
|
|
|
|
}
|
|
|
|
|
|
|
|
int BKE_ccg_factor(int low_level, int high_level)
|
2012-03-14 06:31:24 +00:00
|
|
|
{
|
|
|
|
BLI_assert(low_level > 0 && high_level > 0);
|
|
|
|
BLI_assert(low_level <= high_level);
|
|
|
|
|
|
|
|
return 1 << (high_level - low_level);
|
|
|
|
}
|
|
|
|
|
2012-05-10 20:32:41 +00:00
|
|
|
/***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int num_vert_data = ss->subdivLevels + 1;
|
|
|
|
CCGVert *v = CCGSUBSURF_alloc(
|
2012-04-22 00:20:58 +00:00
|
|
|
ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * num_vert_data + ss->meshIFC.vertUserSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
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);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ss->useAgeCounts) {
|
2012-04-22 00:20:58 +00:00
|
|
|
*((int *)&userData[ss->vertUserAgeOffset]) = ss->currentAge;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _vert_remEdge(CCGVert *v, CCGEdge *e)
|
|
|
|
{
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < v->numEdges; i++) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (v->edges[i] == e) {
|
2005-03-21 01:34:27 +00:00
|
|
|
v->edges[i] = v->edges[--v->numEdges];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _vert_remFace(CCGVert *v, CCGFace *f)
|
|
|
|
{
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < v->numFaces; i++) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (v->faces[i] == f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
v->faces[i] = v->faces[--v->numFaces];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
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));
|
2005-03-21 01:34:27 +00:00
|
|
|
v->edges[v->numEdges++] = e;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
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));
|
2005-03-21 01:34:27 +00:00
|
|
|
v->faces[v->numFaces++] = f;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static CCGEdge *_vert_findEdgeTo(const CCGVert *v, const CCGVert *vQ)
|
|
|
|
{
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < v->numEdges; i++) {
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdge *e = v->edges[v->numEdges - 1 - i]; // XXX, note reverse
|
|
|
|
if ((e->v0 == v && e->v1 == vQ) || (e->v1 == v && e->v0 == vQ)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return e;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2011-02-13 10:52:18 +00:00
|
|
|
return NULL;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _vert_free(CCGVert *v, CCGSubSurf *ss)
|
|
|
|
{
|
2015-02-23 08:33:32 +11:00
|
|
|
if (v->edges) {
|
|
|
|
CCGSUBSURF_free(ss, v->edges);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v->faces) {
|
|
|
|
CCGSUBSURF_free(ss, v->faces);
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGSUBSURF_free(ss, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int num_edge_data = ccg_edgebase(ss->subdivLevels + 1);
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdge *e = CCGSUBSURF_alloc(
|
2012-02-23 07:21:33 +00:00
|
|
|
ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize * num_edge_data + ss->meshIFC.edgeUserSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
byte *userData;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
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);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
userData = ccgSubSurf_getEdgeUserData(ss, e);
|
|
|
|
memset(userData, 0, ss->meshIFC.edgeUserSize);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ss->useAgeCounts) {
|
2012-04-22 00:20:58 +00:00
|
|
|
*((int *)&userData[ss->edgeUserAgeOffset]) = ss->currentAge;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return e;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _edge_remFace(CCGEdge *e, CCGFace *f)
|
|
|
|
{
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < e->numFaces; i++) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (e->faces[i] == f) {
|
2005-03-21 01:34:27 +00:00
|
|
|
e->faces[i] = e->faces[--e->numFaces];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss)
|
|
|
|
{
|
|
|
|
e->faces = CCGSUBSURF_realloc(
|
|
|
|
ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces));
|
2005-03-21 01:34:27 +00:00
|
|
|
e->faces[e->numFaces++] = f;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int levelBase = ccg_edgebase(lvl);
|
2012-02-23 02:17:50 +00:00
|
|
|
if (v == e->v0) {
|
|
|
|
return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
|
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _edge_free(CCGEdge *e, CCGSubSurf *ss)
|
|
|
|
{
|
2015-02-23 08:33:32 +11:00
|
|
|
if (e->faces) {
|
|
|
|
CCGSUBSURF_free(ss, e->faces);
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGSUBSURF_free(ss, e);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
static CCGFace *_face_new(
|
|
|
|
CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int maxGridSize = ccg_gridsize(ss->subdivLevels);
|
|
|
|
int num_face_data = (numVerts * maxGridSize + numVerts * maxGridSize * maxGridSize + 1);
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGFace *f = CCGSUBSURF_alloc(
|
|
|
|
ss,
|
2012-04-22 00:20:58 +00:00
|
|
|
sizeof(CCGFace) + sizeof(CCGVert *) * numVerts + sizeof(CCGEdge *) * numVerts +
|
2012-02-23 07:21:33 +00:00
|
|
|
ss->meshIFC.vertDataSize * num_face_data + ss->meshIFC.faceUserSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
byte *userData;
|
|
|
|
|
|
|
|
f->numVerts = numVerts;
|
|
|
|
f->fHDL = fHDL;
|
|
|
|
f->flags = 0;
|
|
|
|
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < numVerts; i++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
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);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ss->useAgeCounts) {
|
2012-04-22 00:20:58 +00:00
|
|
|
*((int *)&userData[ss->faceUserAgeOffset]) = ss->currentAge;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _face_free(CCGFace *f, CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGSUBSURF_free(ss, f);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
int j;
|
2012-02-23 02:17:50 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
|
|
|
|
int subdivLevels,
|
|
|
|
CCGAllocatorIFC *allocatorIFC,
|
|
|
|
CCGAllocatorHDL allocator)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!allocatorIFC) {
|
2015-07-20 15:05:16 +02:00
|
|
|
allocatorIFC = ccg_getStandardAllocatorIFC();
|
2005-03-21 01:34:27 +00:00
|
|
|
allocator = NULL;
|
|
|
|
}
|
|
|
|
|
2012-04-22 00:20:58 +00:00
|
|
|
if (subdivLevels < 1) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->allocatorIFC = *allocatorIFC;
|
|
|
|
ss->allocator = allocator;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
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);
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->meshIFC = *ifc;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->subdivLevels = subdivLevels;
|
|
|
|
ss->numGrids = 0;
|
|
|
|
ss->allowEdgeCreation = 0;
|
|
|
|
ss->defaultCreaseValue = 0;
|
|
|
|
ss->defaultEdgeUserData = NULL;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->useAgeCounts = 0;
|
|
|
|
ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
|
2005-04-03 21:52:10 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->calcVertNormals = 0;
|
|
|
|
ss->normalDataOffset = 0;
|
Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
have a mask layer and what that layer's offset is. Unlike normals
however, it doesn't change any behavior during CCG calculation; it's
there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
an extra layer is allocated, but the number of CCG layers is not set
to include it. This is done because GridPaintMasks are absolute,
rather than being relative to the subdivided output (as MDisp
displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
set for _getSubSurf(). Related, masks are never loaded in during
ss_sync_from_derivedmesh(). After subdivision is finished, if the
alloc mask flag is set, the number of CCG layers is increase to 4
with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
mask data (e.g. multiresModifier_base_apply.) This flag is always
set in MOD_multires.c so that subdividing a mesh with a mask updates
properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
elements. It's almost the same as the existing operations with xyz
coordinates, but treats masks as absolute rather than displacements
relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
multires_grid_paint_mask_downsample(), which allocates a
lower-resolution paint mask grid and copies values over from the
high-resolution grid.
2012-05-10 20:34:08 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->allocMask = 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
|
|
|
|
ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->currentAge = 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->syncState = eSyncState_None;
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
|
|
|
|
ss->lenTempArrays = 0;
|
|
|
|
ss->tempVerts = NULL;
|
|
|
|
ss->tempEdges = NULL;
|
|
|
|
|
|
|
|
return ss;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
void ccgSubSurf_free(CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
|
|
|
|
CCGAllocatorHDL allocator = ss->allocator;
|
|
|
|
|
|
|
|
if (ss->syncState) {
|
2015-07-20 15:05:16 +02:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
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);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ss->defaultEdgeUserData) {
|
2005-08-20 09:16:09 +00:00
|
|
|
CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
CCGSUBSURF_free(ss, ss);
|
|
|
|
|
|
|
|
if (allocatorIFC.release) {
|
|
|
|
allocatorIFC.release(allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss,
|
|
|
|
int allowEdgeCreation,
|
|
|
|
float defaultCreaseValue,
|
|
|
|
void *defaultUserData)
|
|
|
|
{
|
2005-08-20 09:16:09 +00:00
|
|
|
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);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-08-20 09:16:09 +00:00
|
|
|
memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss,
|
|
|
|
int *allowEdgeCreation_r,
|
|
|
|
float *defaultCreaseValue_r,
|
|
|
|
void *defaultUserData_r)
|
|
|
|
{
|
2019-04-22 09:39:35 +10:00
|
|
|
if (allowEdgeCreation_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
|
|
|
*allowEdgeCreation_r = ss->allowEdgeCreation;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-20 09:16:09 +00:00
|
|
|
if (ss->allowEdgeCreation) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (defaultCreaseValue_r) {
|
2005-08-20 09:16:09 +00:00
|
|
|
*defaultCreaseValue_r = ss->defaultCreaseValue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (defaultUserData_r) {
|
2005-08-20 09:16:09 +00:00
|
|
|
memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-08-20 09:16:09 +00:00
|
|
|
}
|
- 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
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (subdivisionLevels <= 0) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidValue;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
if (subdivisionLevels != ss->subdivLevels) {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->numGrids = 0;
|
|
|
|
ss->subdivLevels = subdivisionLevels;
|
2015-07-20 15:05:16 +02:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
- 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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (vertUserOffset_r) {
|
- 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
|
|
|
*vertUserOffset_r = ss->vertUserAgeOffset;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (edgeUserOffset_r) {
|
- 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
|
|
|
*edgeUserOffset_r = ss->edgeUserAgeOffset;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (faceUserOffset_r) {
|
- 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
|
|
|
*faceUserOffset_r = ss->faceUserAgeOffset;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
- 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
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_setUseAgeCounts(
|
|
|
|
CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
if (useAgeCounts) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if ((vertUserOffset + 4 > ss->meshIFC.vertUserSize) ||
|
|
|
|
(edgeUserOffset + 4 > ss->meshIFC.edgeUserSize) ||
|
|
|
|
(faceUserOffset + 4 > ss->meshIFC.faceUserSize)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidValue;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->useAgeCounts = 1;
|
|
|
|
ss->vertUserAgeOffset = vertUserOffset;
|
|
|
|
ss->edgeUserAgeOffset = edgeUserOffset;
|
|
|
|
ss->faceUserAgeOffset = faceUserOffset;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->useAgeCounts = 0;
|
|
|
|
ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset)
|
|
|
|
{
|
2005-04-03 21:52:10 +00:00
|
|
|
if (useVertNormals) {
|
2012-04-22 00:20:58 +00:00
|
|
|
if (normalDataOffset < 0 || normalDataOffset + 12 > ss->meshIFC.vertDataSize) {
|
2005-04-03 21:52:10 +00:00
|
|
|
return eCCGError_InvalidValue;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
ss->calcVertNormals = 1;
|
|
|
|
ss->normalDataOffset = normalDataOffset;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-04-03 21:52:10 +00:00
|
|
|
ss->calcVertNormals = 0;
|
|
|
|
ss->normalDataOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
have a mask layer and what that layer's offset is. Unlike normals
however, it doesn't change any behavior during CCG calculation; it's
there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
an extra layer is allocated, but the number of CCG layers is not set
to include it. This is done because GridPaintMasks are absolute,
rather than being relative to the subdivided output (as MDisp
displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
set for _getSubSurf(). Related, masks are never loaded in during
ss_sync_from_derivedmesh(). After subdivision is finished, if the
alloc mask flag is set, the number of CCG layers is increase to 4
with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
mask data (e.g. multiresModifier_base_apply.) This flag is always
set in MOD_multires.c so that subdividing a mesh with a mask updates
properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
elements. It's almost the same as the existing operations with xyz
coordinates, but treats masks as absolute rather than displacements
relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
multires_grid_paint_mask_downsample(), which allocates a
lower-resolution paint mask grid and copies values over from the
high-resolution grid.
2012-05-10 20:34:08 +00:00
|
|
|
void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset)
|
|
|
|
{
|
|
|
|
ss->allocMask = allocMask;
|
|
|
|
ss->maskDataOffset = maskOffset;
|
|
|
|
}
|
|
|
|
|
2012-05-10 20:32:41 +00:00
|
|
|
void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers)
|
|
|
|
{
|
|
|
|
ss->meshIFC.numLayers = numLayers;
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_None) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss->currentAge++;
|
|
|
|
|
2018-06-17 17:05:51 +02:00
|
|
|
ss->oldVMap = ss->vMap;
|
|
|
|
ss->oldEMap = ss->eMap;
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->oldFMap = ss->fMap;
|
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
|
|
|
|
ss->numGrids = 0;
|
|
|
|
|
|
|
|
ss->lenTempArrays = 12;
|
2012-02-23 02:17:50 +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;
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_None) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss->currentAge++;
|
|
|
|
|
|
|
|
ss->syncState = eSyncState_Partial;
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_Partial) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
void **prevp;
|
|
|
|
CCGVert *v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
|
|
|
|
|
|
|
|
if (!v || v->numFaces || v->numEdges) {
|
|
|
|
return eCCGError_InvalidValue;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
*prevp = v->next;
|
|
|
|
_vert_free(v, ss);
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_Partial) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
void **prevp;
|
|
|
|
CCGEdge *e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
|
|
|
|
|
|
|
|
if (!e || e->numFaces) {
|
|
|
|
return eCCGError_InvalidValue;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
*prevp = e->next;
|
|
|
|
_edge_unlinkMarkAndFree(e, ss);
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_Partial) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
void **prevp;
|
|
|
|
CCGFace *f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
|
|
|
|
|
|
|
|
if (!f) {
|
|
|
|
return eCCGError_InvalidValue;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-03 18:04:40 +02:00
|
|
|
*prevp = f->next;
|
|
|
|
_face_unlinkMarkAndFree(f, ss);
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_syncVert(
|
|
|
|
CCGSubSurf *ss, CCGVertHDL vHDL, const 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;
|
2012-04-22 00:20:58 +00:00
|
|
|
short seamflag = (seam) ? Vert_eSeam : 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (ss->syncState == eSyncState_Partial) {
|
2015-07-20 15:05:16 +02:00
|
|
|
v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!v) {
|
2008-09-29 17:08:11 +00:00
|
|
|
v = _vert_new(vHDL, ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
|
|
|
|
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
|
2012-04-22 00:20:58 +00:00
|
|
|
v->flags = Vert_eEffected | seamflag;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2015-07-20 15:05:16 +02:00
|
|
|
else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
|
2012-05-12 16:11:34 +00:00
|
|
|
((v->flags & Vert_eSeam) != seamflag)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
int i, j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
|
2012-04-22 00:20:58 +00:00
|
|
|
v->flags = Vert_eEffected | seamflag;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < v->numEdges; i++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGEdge *e = v->edges[i];
|
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < v->numFaces; i++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
CCGFace *f = v->faces[i];
|
2012-02-23 02:17:50 +00:00
|
|
|
for (j = 0; j < f->numVerts; j++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
FACE_getVerts(f)[j]->flags |= Vert_eEffected;
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
else {
|
2012-04-22 00:20:58 +00:00
|
|
|
if (ss->syncState != eSyncState_Vert) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
v = ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!v) {
|
2008-09-29 17:08:11 +00:00
|
|
|
v = _vert_new(vHDL, ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
|
|
|
|
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
|
2012-04-22 00:20:58 +00:00
|
|
|
v->flags = Vert_eEffected | seamflag;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2015-07-20 15:05:16 +02:00
|
|
|
else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
|
2012-05-20 19:49:27 +00:00
|
|
|
((v->flags & Vert_eSeam) != seamflag)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = v->next;
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
|
|
|
|
VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
|
2012-04-22 00:20:58 +00:00
|
|
|
v->flags = Vert_eEffected | Vert_eChanged | seamflag;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = v->next;
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
|
2005-03-21 01:34:27 +00:00
|
|
|
v->flags = 0;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (v_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
|
|
|
*v_r = v;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (ss->syncState == eSyncState_Partial) {
|
2015-07-20 15:05:16 +02:00
|
|
|
e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
|
2012-04-22 00:20:58 +00:00
|
|
|
if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) {
|
2015-07-20 15:05:16 +02:00
|
|
|
CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
|
|
|
|
CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-09-29 17:08:11 +00:00
|
|
|
eNew = _edge_new(eHDL, v0, v1, crease, ss);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (e) {
|
|
|
|
*prevp = eNew;
|
|
|
|
eNew->next = e->next;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
_edge_unlinkMarkAndFree(e, ss);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->eMap, (EHEntry *)eNew);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
eNew->v0->flags |= Vert_eEffected;
|
|
|
|
eNew->v1->flags |= Vert_eEffected;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
else {
|
|
|
|
if (ss->syncState == eSyncState_Vert) {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->syncState = eSyncState_Edge;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2012-04-22 00:20:58 +00:00
|
|
|
else if (ss->syncState != eSyncState_Edge) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
e = ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
|
2012-04-22 00:20:58 +00:00
|
|
|
if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) {
|
2015-07-20 15:05:16 +02:00
|
|
|
CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
|
|
|
|
CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
|
2008-09-29 17:08:11 +00:00
|
|
|
e = _edge_new(eHDL, v0, v1, crease, ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->eMap, (EHEntry *)e);
|
2005-03-21 01:34:27 +00:00
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = e->next;
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->eMap, (EHEntry *)e);
|
2005-03-21 01:34:27 +00:00
|
|
|
e->flags = 0;
|
2012-04-22 00:20:58 +00:00
|
|
|
if ((e->v0->flags | e->v1->flags) & Vert_eChanged) {
|
2005-03-21 01:34:27 +00:00
|
|
|
e->v0->flags |= Vert_eEffected;
|
|
|
|
e->v1->flags |= Vert_eEffected;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (e_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
|
|
|
*e_r = e;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-14 11:07:33 +10:00
|
|
|
if (UNLIKELY(numVerts > ss->lenTempArrays)) {
|
2012-02-23 02:17:50 +00:00
|
|
|
ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts;
|
|
|
|
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
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (ss->syncState == eSyncState_Partial) {
|
2015-07-20 15:05:16 +02:00
|
|
|
f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
2015-07-20 15:05:16 +02:00
|
|
|
ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
|
|
|
ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (f) {
|
2012-04-22 00:20:58 +00:00
|
|
|
if (f->numVerts != numVerts ||
|
2020-08-07 17:16:46 +02:00
|
|
|
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 ||
|
|
|
|
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0) {
|
2005-03-21 01:34:27 +00:00
|
|
|
topologyChanged = 1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!f || topologyChanged) {
|
2008-09-29 17:08:11 +00:00
|
|
|
fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (f) {
|
|
|
|
ss->numGrids += numVerts - f->numVerts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = fNew;
|
|
|
|
fNew->next = f->next;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
_face_unlinkMarkAndFree(f, ss);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->numGrids += numVerts;
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->fMap, (EHEntry *)fNew);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
else {
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(ss->syncState, eSyncState_Vert, eSyncState_Edge)) {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->syncState = eSyncState_Face;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2012-04-22 00:20:58 +00:00
|
|
|
else if (ss->syncState != eSyncState_Face) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
f = ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
2015-07-20 15:05:16 +02:00
|
|
|
ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!ss->tempVerts[k]) {
|
2005-08-03 19:27:19 +00:00
|
|
|
return eCCGError_InvalidValue;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
|
|
|
ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-08-03 19:27:19 +00:00
|
|
|
if (!ss->tempEdges[k]) {
|
|
|
|
if (ss->allowEdgeCreation) {
|
2012-04-22 00:20:58 +00:00
|
|
|
CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL)-1,
|
|
|
|
ss->tempVerts[k],
|
|
|
|
ss->tempVerts[(k + 1) % numVerts],
|
|
|
|
ss->defaultCreaseValue,
|
|
|
|
ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->eMap, (EHEntry *)e);
|
2005-08-03 19:27:19 +00:00
|
|
|
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);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
else {
|
2005-08-03 19:27:19 +00:00
|
|
|
return eCCGError_InvalidValue;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (f) {
|
2012-04-22 00:20:58 +00:00
|
|
|
if (f->numVerts != numVerts ||
|
2020-08-07 17:16:46 +02:00
|
|
|
memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 ||
|
|
|
|
memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0) {
|
2005-03-21 01:34:27 +00:00
|
|
|
topologyChanged = 1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
if (!f || topologyChanged) {
|
2008-09-29 17:08:11 +00:00
|
|
|
f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->fMap, (EHEntry *)f);
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->numGrids += numVerts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (k = 0; k < numVerts; k++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
FACE_getVerts(f)[k]->flags |= Vert_eEffected;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
*prevp = f->next;
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehash_insert(ss->fMap, (EHEntry *)f);
|
2005-03-21 01:34:27 +00:00
|
|
|
f->flags = 0;
|
|
|
|
ss->numGrids += f->numVerts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (j = 0; j < f->numVerts; j++) {
|
|
|
|
if (FACE_getVerts(f)[j]->flags & Vert_eChanged) {
|
2019-04-22 09:39:35 +10:00
|
|
|
for (k = 0; k < f->numVerts; k++) {
|
2005-03-21 01:34:27 +00:00
|
|
|
FACE_getVerts(f)[k]->flags |= Vert_eEffected;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (f_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
|
|
|
*f_r = f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
static void ccgSubSurf__sync(CCGSubSurf *ss)
|
|
|
|
{
|
2020-05-18 16:42:59 +02:00
|
|
|
ccgSubSurf__sync_legacy(ss);
|
2015-07-20 15:05:16 +02:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
|
|
|
|
{
|
|
|
|
if (ss->syncState == eSyncState_Partial) {
|
2005-03-21 01:34:27 +00:00
|
|
|
ss->syncState = eSyncState_None;
|
|
|
|
|
|
|
|
ccgSubSurf__sync(ss);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else if (ss->syncState) {
|
2015-07-20 15:05:16 +02:00
|
|
|
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);
|
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);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-03-21 01:34:27 +00:00
|
|
|
return eCCGError_InvalidSyncState;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eCCGError_None;
|
|
|
|
}
|
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
|
|
|
|
{
|
|
|
|
CCGFace **array;
|
|
|
|
int i, num;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-20 15:05:16 +02:00
|
|
|
if (*faces == NULL) {
|
|
|
|
array = 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];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (; f; f = f->next) {
|
2015-07-20 15:05:16 +02:00
|
|
|
array[num++] = f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2015-07-20 15:05:16 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
*faces = array;
|
|
|
|
*numFaces = num;
|
2012-02-23 02:17:50 +00:00
|
|
|
*freeFaces = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*freeFaces = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-06 17:09:07 +10:00
|
|
|
void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
|
|
|
|
CCGFace **faces,
|
|
|
|
int numFaces,
|
|
|
|
CCGVert ***verts,
|
|
|
|
int *numVerts,
|
|
|
|
CCGEdge ***edges,
|
|
|
|
int *numEdges)
|
2009-11-25 12:27:21 +00:00
|
|
|
{
|
|
|
|
CCGVert **arrayV;
|
|
|
|
CCGEdge **arrayE;
|
|
|
|
int numV, numE, i, j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numFaces; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGFace *f = faces[i];
|
|
|
|
f->flags |= Face_eEffected;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < ss->vMap->curSize; i++) {
|
2012-04-22 00:20:58 +00:00
|
|
|
CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (; v; v = v->next) {
|
2019-04-22 09:39:35 +10:00
|
|
|
for (j = 0; j < v->numFaces; j++) {
|
|
|
|
if (!(v->faces[j]->flags & Face_eEffected)) {
|
2009-11-25 12:27:21 +00:00
|
|
|
break;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (j == v->numFaces) {
|
2009-11-25 12:27:21 +00:00
|
|
|
arrayV[numV++] = v;
|
|
|
|
v->flags |= Vert_eEffected;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < ss->eMap->curSize; i++) {
|
2012-04-22 00:20:58 +00:00
|
|
|
CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
for (; e; e = e->next) {
|
2019-04-22 09:39:35 +10:00
|
|
|
for (j = 0; j < e->numFaces; j++) {
|
|
|
|
if (!(e->faces[j]->flags & Face_eEffected)) {
|
2009-11-25 12:27:21 +00:00
|
|
|
break;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (j == e->numFaces) {
|
2009-11-25 12:27:21 +00:00
|
|
|
e->flags |= Edge_eEffected;
|
|
|
|
arrayE[numE++] = e;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02: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;
|
2012-04-22 00:20:58 +00:00
|
|
|
lvl = (lvl) ? lvl : subdivLevels;
|
2012-02-23 07:21:33 +00:00
|
|
|
gridSize = ccg_gridsize(lvl);
|
2012-02-23 02:17:50 +00:00
|
|
|
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
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGFace *f = effectedF[i];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataCopy((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(
|
|
|
|
VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss);
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (x = 0; x < gridSize; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-22 06:11:25 +00:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
int eI = gridSize - 1 - x;
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
FACE_getIFCo(f, lvl, S, cornerIdx, x),
|
|
|
|
ss);
|
|
|
|
VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
FACE_getIFCo(f, lvl, S, x, cornerIdx),
|
|
|
|
ss);
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2005-04-01 02:52:55 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (freeF) {
|
2012-02-23 02:17:50 +00:00
|
|
|
MEM_freeN(effectedF);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
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;
|
2012-04-22 00:20:58 +00:00
|
|
|
lvl = (lvl) ? lvl : subdivLevels;
|
2012-02-23 07:21:33 +00:00
|
|
|
gridSize = ccg_gridsize(lvl);
|
2012-02-23 02:17:50 +00:00
|
|
|
cornerIdx = gridSize - 1;
|
2009-12-11 10:56:20 +00:00
|
|
|
|
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
2009-12-11 10:56:20 +00:00
|
|
|
CCGFace *f = effectedF[i];
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
|
|
int prevS = (S + f->numVerts - 1) % f->numVerts;
|
2009-12-11 10:56:20 +00:00
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
int eI = gridSize - 1 - x;
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x),
|
|
|
|
_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
ss);
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
|
|
|
|
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
ss);
|
2009-12-11 10:56:20 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 1; x < gridSize - 1; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
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);
|
2009-12-11 10:56:20 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(
|
|
|
|
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
|
2009-12-11 10:56:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (freeF) {
|
2012-02-23 02:17:50 +00:00
|
|
|
MEM_freeN(effectedF);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
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
|
2012-03-03 20:19:11 +00:00
|
|
|
* and vertices, for multires displacements */
|
2009-11-25 12:27:21 +00:00
|
|
|
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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
subdivLevels = ss->subdivLevels;
|
2012-04-22 00:20:58 +00:00
|
|
|
lvl = (lvl) ? lvl : subdivLevels;
|
2012-02-23 07:21:33 +00:00
|
|
|
gridSize = ccg_gridsize(lvl);
|
|
|
|
edgeSize = ccg_edgesize(lvl);
|
2012-02-23 02:17:50 +00:00
|
|
|
cornerIdx = gridSize - 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
2019-08-06 17:09:07 +10:00
|
|
|
ccgSubSurf__effectedFaceNeighbors(
|
2012-04-22 00:20:58 +00:00
|
|
|
ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* zero */
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedV; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGVert *v = effectedV[i];
|
2019-04-22 09:39:35 +10:00
|
|
|
if (v->numFaces) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataZero(VERT_getCo(v, lvl), ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedE; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGEdge *e = effectedE[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (e->numFaces) {
|
|
|
|
for (x = 0; x < edgeSize; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataZero(EDGE_getCo(e, lvl, x), ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* add */
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGFace *f = effectedF[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataZero((float *)FACE_getCenterData(f), ss);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
|
|
for (x = 0; x < gridSize; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataZero(FACE_getIECo(f, lvl, S, x), ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
|
|
int prevS = (S + f->numVerts - 1) % f->numVerts;
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataAdd((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl),
|
|
|
|
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx),
|
|
|
|
ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 1; x < gridSize - 1; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
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);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
|
|
int eI = gridSize - 1 - x;
|
2019-04-22 09:39:35 +10:00
|
|
|
if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
FACE_getIFCo(f, lvl, S, cornerIdx, x),
|
|
|
|
ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (FACE_getEdges(f)[prevS]->flags & Edge_eEffected) {
|
|
|
|
if (x != 0) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
FACE_getIFCo(f, lvl, S, x, cornerIdx),
|
|
|
|
ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* average */
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedV; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGVert *v = effectedV[i];
|
2019-04-22 09:39:35 +10:00
|
|
|
if (v->numFaces) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataMulN(VERT_getCo(v, lvl), 1.0f / v->numFaces, ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedE; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGEdge *e = effectedE[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-10 20:32:41 +00:00
|
|
|
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);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (e->numFaces) {
|
|
|
|
for (x = 1; x < edgeSize - 1; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f / e->numFaces, ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
/* copy */
|
2012-02-23 02:17:50 +00:00
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGFace *f = effectedF[i];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
|
|
for (x = 1; x < gridSize - 1; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, ss);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
|
|
int prevS = (S + f->numVerts - 1) % f->numVerts;
|
2009-11-25 12:27:21 +00:00
|
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
|
|
CCGEdge *prevE = FACE_getEdges(f)[prevS];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(
|
|
|
|
FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 1; x < gridSize - 1; x++) {
|
2012-05-10 20:32:41 +00:00
|
|
|
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);
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
|
|
int eI = gridSize - 1 - x;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x),
|
|
|
|
_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
ss);
|
|
|
|
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
|
|
|
|
_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
|
|
|
|
ss);
|
2005-04-03 21:52:10 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
VertDataCopy(FACE_getIECo(f, lvl, S, 0), (float *)FACE_getCenterData(f), ss);
|
2012-05-10 20:32:41 +00:00
|
|
|
VertDataCopy(
|
|
|
|
FACE_getIECo(f, lvl, S, gridSize - 1), FACE_getIFCo(f, lvl, S, gridSize - 1, 0), ss);
|
2005-04-03 21:52:10 +00:00
|
|
|
}
|
2009-11-25 12:27:21 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (i = 0; i < numEffectedV; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
effectedV[i]->flags = 0;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
for (i = 0; i < numEffectedE; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
effectedE[i]->flags = 0;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
2009-11-25 12:27:21 +00:00
|
|
|
effectedF[i]->flags = 0;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-08 15:01:11 +00:00
|
|
|
MEM_freeN(effectedE);
|
|
|
|
MEM_freeN(effectedV);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (freeF) {
|
2012-02-23 02:17:50 +00:00
|
|
|
MEM_freeN(effectedF);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-25 12:27:21 +00:00
|
|
|
return eCCGError_None;
|
|
|
|
}
|
2005-08-03 04:04:05 +00:00
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/*** External API accessor functions ***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumVerts(const CCGSubSurf *ss)
|
|
|
|
{
|
2015-08-03 16:44:46 +02:00
|
|
|
return ss->vMap->numEntries;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumEdges(const CCGSubSurf *ss)
|
|
|
|
{
|
2015-08-03 16:44:46 +02:00
|
|
|
return ss->eMap->numEntries;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumFaces(const CCGSubSurf *ss)
|
|
|
|
{
|
2015-08-03 16:44:46 +02:00
|
|
|
return ss->fMap->numEntries;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return (CCGVert *)ccg_ehash_lookup(ss->vMap, v);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return (CCGEdge *)ccg_ehash_lookup(ss->eMap, e);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return (CCGFace *)ccg_ehash_lookup(ss->fMap, f);
|
2005-03-22 06:11:25 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ss->subdivLevels;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (level < 1 || level > ss->subdivLevels) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return -1;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return ccg_edgesize(level);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getGridSize(const CCGSubSurf *ss)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (level < 1 || level > ss->subdivLevels) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return -1;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return ccg_gridsize(level);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2012-08-18 19:54:21 +00:00
|
|
|
int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss)
|
|
|
|
{
|
|
|
|
return ss->meshIFC.simpleSubdiv;
|
|
|
|
}
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
/* Vert accessors */
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->vHDL;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getVertUserData(ss, v);
|
2012-04-22 00:20:58 +00:00
|
|
|
return ss->currentAge - *((int *)&userData[ss->vertUserAgeOffset]);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v)
|
|
|
|
{
|
|
|
|
return VERT_getLevelData(v) + ss->meshIFC.vertDataSize * (ss->subdivLevels + 1);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getVertNumFaces(CCGVert *v)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->numFaces;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (index < 0 || index >= v->numFaces) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return v->faces[index];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getVertNumEdges(CCGVert *v)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return v->numEdges;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (index < 0 || index >= v->numEdges) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return v->edges[index];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (level < 0 || level > ss->subdivLevels) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Edge accessors */
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->eHDL;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
|
2012-04-22 00:20:58 +00:00
|
|
|
return ss->currentAge - *((int *)&userData[ss->edgeUserAgeOffset]);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
return (EDGE_getLevelData(e) + ss->meshIFC.vertDataSize * ccg_edgebase(ss->subdivLevels + 1));
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getEdgeNumFaces(CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->numFaces;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (index < 0 || index >= e->numFaces) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return e->faces[index];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->v0;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return e->v1;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getEdgeData(ss, e, 0);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level)
|
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (level < 0 || level > ss->subdivLevels) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +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 */
|
|
|
|
|
2012-03-06 01:01:42 +00:00
|
|
|
CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return f->fHDL;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
if (ss->useAgeCounts) {
|
|
|
|
byte *userData = ccgSubSurf_getFaceUserData(ss, f);
|
2012-04-22 00:20:58 +00:00
|
|
|
return ss->currentAge - *((int *)&userData[ss->faceUserAgeOffset]);
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return 0;
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int maxGridSize = ccg_gridsize(ss->subdivLevels);
|
2012-02-23 02:17:50 +00:00
|
|
|
return FACE_getCenterData(f) +
|
|
|
|
ss->meshIFC.vertDataSize *
|
|
|
|
(1 + f->numVerts * maxGridSize + f->numVerts * maxGridSize * maxGridSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getFaceNumVerts(CCGFace *f)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return f->numVerts;
|
|
|
|
}
|
2012-03-06 01:01:42 +00:00
|
|
|
CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (index < 0 || index >= f->numVerts) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return FACE_getVerts(f)[index];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-03-06 01:01:42 +00:00
|
|
|
CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2012-04-22 00:20:58 +00:00
|
|
|
if (index < 0 || index >= f->numVerts) {
|
2005-03-21 01:34:27 +00:00
|
|
|
return NULL;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
2020-07-03 18:04:40 +02:00
|
|
|
return FACE_getEdges(f)[index];
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e)
|
|
|
|
{
|
2020-09-09 15:43:09 +02:00
|
|
|
for (int i = 0; i < f->numVerts; i++) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (FACE_getEdges(f)[i] == e) {
|
2005-08-18 11:31:20 +00:00
|
|
|
return i;
|
2012-02-23 02:17:50 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-18 11:31:20 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceCenterData(CCGFace *f)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return FACE_getCenterData(f);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return ccg_face_getIECo(
|
|
|
|
f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex)
|
|
|
|
{
|
2005-03-21 01:34:27 +00:00
|
|
|
return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return ccg_face_getIFCo(
|
|
|
|
f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*** External API iterator functions ***/
|
|
|
|
|
2014-12-10 11:06:00 +01:00
|
|
|
void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehashIterator_init(ss->vMap, viter);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2014-12-10 11:06:00 +01:00
|
|
|
void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehashIterator_init(ss->eMap, eiter);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2014-12-10 11:06:00 +01:00
|
|
|
void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehashIterator_init(ss->fMap, fiter);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return (CCGVert *)ccg_ehashIterator_getCurrent((EHashIterator *)vi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgVertIterator_isStopped(CCGVertIterator *vi)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
return ccg_ehashIterator_isStopped((EHashIterator *)vi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
void ccgVertIterator_next(CCGVertIterator *vi)
|
|
|
|
{
|
2015-07-20 15:05:16 +02:00
|
|
|
ccg_ehashIterator_next((EHashIterator *)vi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *ei)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
return (CCGEdge *)ccg_ehashIterator_getCurrent((EHashIterator *)ei);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
int ccgEdgeIterator_isStopped(CCGEdgeIterator *ei)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
return ccg_ehashIterator_isStopped((EHashIterator *)ei);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void ccgEdgeIterator_next(CCGEdgeIterator *ei)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
ccg_ehashIterator_next((EHashIterator *)ei);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
return (CCGFace *)ccg_ehashIterator_getCurrent((EHashIterator *)fi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
int ccgFaceIterator_isStopped(CCGFaceIterator *fi)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
return ccg_ehashIterator_isStopped((EHashIterator *)fi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void ccgFaceIterator_next(CCGFaceIterator *fi)
|
2012-02-23 02:17:50 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
ccg_ehashIterator_next((EHashIterator *)fi);
|
2005-03-21 01:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*** Extern API final vert/edge/face interface ***/
|
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int edgeSize = ccg_edgesize(ss->subdivLevels);
|
|
|
|
int gridSize = ccg_gridsize(ss->subdivLevels);
|
2012-02-23 02:17:50 +00:00
|
|
|
int numFinalVerts = (ss->vMap->numEntries + ss->eMap->numEntries * (edgeSize - 2) +
|
|
|
|
ss->fMap->numEntries +
|
|
|
|
ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2))));
|
|
|
|
|
2005-03-21 01:34:27 +00:00
|
|
|
return numFinalVerts;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int edgeSize = ccg_edgesize(ss->subdivLevels);
|
|
|
|
int gridSize = ccg_gridsize(ss->subdivLevels);
|
2012-02-23 02:17:50 +00:00
|
|
|
int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
|
|
|
|
ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
|
2005-03-21 01:34:27 +00:00
|
|
|
return numFinalEdges;
|
|
|
|
}
|
2012-02-23 02:17:50 +00:00
|
|
|
int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss)
|
|
|
|
{
|
2012-02-23 07:21:33 +00:00
|
|
|
int gridSize = ccg_gridsize(ss->subdivLevels);
|
2012-02-23 02:17:50 +00:00
|
|
|
int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
|
2005-03-21 01:34:27 +00:00
|
|
|
return numFinalFaces;
|
|
|
|
}
|
2012-05-10 20:32:51 +00:00
|
|
|
|
|
|
|
/***/
|
|
|
|
|
|
|
|
void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level)
|
|
|
|
{
|
|
|
|
key->level = level;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2012-05-10 20:32:51 +00:00
|
|
|
key->elem_size = ss->meshIFC.vertDataSize;
|
|
|
|
key->has_normals = ss->calcVertNormals;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2012-05-10 20:32:51 +00:00
|
|
|
/* if normals are present, always the last three floats of an
|
2012-05-16 23:37:23 +00:00
|
|
|
* element */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (key->has_normals) {
|
2020-08-08 13:29:21 +10:00
|
|
|
key->normal_offset = key->elem_size - sizeof(float[3]);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
else {
|
2012-05-10 20:32:51 +00:00
|
|
|
key->normal_offset = -1;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-05-10 20:32:51 +00:00
|
|
|
|
|
|
|
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;
|
Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
have a mask layer and what that layer's offset is. Unlike normals
however, it doesn't change any behavior during CCG calculation; it's
there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
an extra layer is allocated, but the number of CCG layers is not set
to include it. This is done because GridPaintMasks are absolute,
rather than being relative to the subdivided output (as MDisp
displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
set for _getSubSurf(). Related, masks are never loaded in during
ss_sync_from_derivedmesh(). After subdivision is finished, if the
alloc mask flag is set, the number of CCG layers is increase to 4
with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
mask data (e.g. multiresModifier_base_apply.) This flag is always
set in MOD_multires.c so that subdividing a mesh with a mask updates
properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
elements. It's almost the same as the existing operations with xyz
coordinates, but treats masks as absolute rather than displacements
relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
multires_grid_paint_mask_downsample(), which allocates a
lower-resolution paint mask grid and copies values over from the
high-resolution grid.
2012-05-10 20:34:08 +00:00
|
|
|
|
|
|
|
key->has_mask = ss->allocMask;
|
2019-04-22 09:39:35 +10:00
|
|
|
if (key->has_mask) {
|
Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
have a mask layer and what that layer's offset is. Unlike normals
however, it doesn't change any behavior during CCG calculation; it's
there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
an extra layer is allocated, but the number of CCG layers is not set
to include it. This is done because GridPaintMasks are absolute,
rather than being relative to the subdivided output (as MDisp
displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
set for _getSubSurf(). Related, masks are never loaded in during
ss_sync_from_derivedmesh(). After subdivision is finished, if the
alloc mask flag is set, the number of CCG layers is increase to 4
with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
mask data (e.g. multiresModifier_base_apply.) This flag is always
set in MOD_multires.c so that subdividing a mesh with a mask updates
properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
elements. It's almost the same as the existing operations with xyz
coordinates, but treats masks as absolute rather than displacements
relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
multires_grid_paint_mask_downsample(), which allocates a
lower-resolution paint mask grid and copies values over from the
high-resolution grid.
2012-05-10 20:34:08 +00:00
|
|
|
key->mask_offset = ss->maskDataOffset;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
else {
|
Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
have a mask layer and what that layer's offset is. Unlike normals
however, it doesn't change any behavior during CCG calculation; it's
there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
an extra layer is allocated, but the number of CCG layers is not set
to include it. This is done because GridPaintMasks are absolute,
rather than being relative to the subdivided output (as MDisp
displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
set for _getSubSurf(). Related, masks are never loaded in during
ss_sync_from_derivedmesh(). After subdivision is finished, if the
alloc mask flag is set, the number of CCG layers is increase to 4
with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
mask data (e.g. multiresModifier_base_apply.) This flag is always
set in MOD_multires.c so that subdividing a mesh with a mask updates
properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
elements. It's almost the same as the existing operations with xyz
coordinates, but treats masks as absolute rather than displacements
relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
multires_grid_paint_mask_downsample(), which allocates a
lower-resolution paint mask grid and copies values over from the
high-resolution grid.
2012-05-10 20:34:08 +00:00
|
|
|
key->mask_offset = -1;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-05-10 20:32:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss)
|
|
|
|
{
|
|
|
|
CCG_key(key, ss, ccgSubSurf_getSubdivisionLevels(ss));
|
|
|
|
}
|