Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
1376 lines
44 KiB
C++
1376 lines
44 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include "BLI_sys_types.h" /* for intptr_t support */
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_task.h"
|
|
#include "BLI_utildefines.h" /* for BLI_assert */
|
|
|
|
#include "CCGSubSurf.h"
|
|
#include "CCGSubSurf_intern.h"
|
|
|
|
#define FACE_calcIFNo(f, lvl, S, x, y, no) \
|
|
_face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
|
|
|
|
/* TODO(sergey): Deduplicate the following functions/ */
|
|
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize)
|
|
{
|
|
int levelBase = ccg_edgebase(lvl);
|
|
if (v == e->v0) {
|
|
return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
|
|
}
|
|
return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
|
|
}
|
|
/* *************************************************** */
|
|
|
|
static int _edge_isBoundary(const CCGEdge *e)
|
|
{
|
|
return e->numFaces < 2;
|
|
}
|
|
|
|
static bool _vert_isBoundary(const CCGVert *v)
|
|
{
|
|
for (int i = 0; i < v->numEdges; i++) {
|
|
if (_edge_isBoundary(v->edges[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ)
|
|
{
|
|
if (vQ == e->v0) {
|
|
return e->v1;
|
|
}
|
|
|
|
return e->v0;
|
|
}
|
|
|
|
static float *_face_getIFNoEdge(CCGFace *f,
|
|
CCGEdge *e,
|
|
int f_ed_idx,
|
|
int lvl,
|
|
int eX,
|
|
int eY,
|
|
int levels,
|
|
int dataSize,
|
|
int normalDataOffset)
|
|
{
|
|
return (float *)((byte *)ccg_face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) +
|
|
normalDataOffset);
|
|
}
|
|
|
|
static void _face_calcIFNo(
|
|
CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize)
|
|
{
|
|
float *a = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize));
|
|
float *b = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize));
|
|
float *c = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize));
|
|
float *d = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize));
|
|
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
|
|
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
|
|
|
|
no[0] = b_dY * a_cZ - b_dZ * a_cY;
|
|
no[1] = b_dZ * a_cX - b_dX * a_cZ;
|
|
no[2] = b_dX * a_cY - b_dY * a_cX;
|
|
|
|
Normalize(no);
|
|
}
|
|
|
|
static int VERT_seam(const CCGVert *v)
|
|
{
|
|
return ((v->flags & Vert_eSeam) != 0);
|
|
}
|
|
|
|
static float EDGE_getSharpness(CCGEdge *e, int lvl)
|
|
{
|
|
if (!lvl) {
|
|
return e->crease;
|
|
}
|
|
if (!e->crease) {
|
|
return 0.0f;
|
|
}
|
|
if (e->crease - lvl < 0.0f) {
|
|
return 0.0f;
|
|
}
|
|
return e->crease - lvl;
|
|
}
|
|
|
|
struct CCGSubSurfCalcSubdivData {
|
|
CCGSubSurf *ss;
|
|
CCGVert **effectedV;
|
|
CCGEdge **effectedE;
|
|
CCGFace **effectedF;
|
|
int numEffectedV;
|
|
int numEffectedE;
|
|
int numEffectedF;
|
|
|
|
int curLvl;
|
|
};
|
|
|
|
static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGFace *f = data->effectedF[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int lvl = ss->subdivLevels;
|
|
const int gridSize = ccg_gridsize(lvl);
|
|
const int normalDataOffset = ss->normalDataOffset;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
int S, x, y;
|
|
float no[3];
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
for (y = 0; y < gridSize - 1; y++) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
NormZero(FACE_getIFNo(f, lvl, S, x, y));
|
|
}
|
|
}
|
|
|
|
if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1));
|
|
}
|
|
}
|
|
if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
|
|
for (y = 0; y < gridSize - 1; y++) {
|
|
NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y));
|
|
}
|
|
}
|
|
if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
|
|
NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1));
|
|
}
|
|
}
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected);
|
|
int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected);
|
|
int yLimitNext = xLimit;
|
|
int xLimitPrev = yLimit;
|
|
|
|
for (y = 0; y < gridSize - 1; y++) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
int xPlusOk = (!xLimit || x < gridSize - 2);
|
|
int yPlusOk = (!yLimit || y < gridSize - 2);
|
|
|
|
FACE_calcIFNo(f, lvl, S, x, y, no);
|
|
|
|
NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no);
|
|
if (xPlusOk) {
|
|
NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no);
|
|
}
|
|
if (yPlusOk) {
|
|
NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no);
|
|
}
|
|
if (xPlusOk && yPlusOk) {
|
|
if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected)
|
|
{
|
|
NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no);
|
|
}
|
|
}
|
|
|
|
if (x == 0 && y == 0) {
|
|
int K;
|
|
|
|
if (!yLimitNext || 1 < gridSize - 1) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no);
|
|
}
|
|
if (!xLimitPrev || 1 < gridSize - 1) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no);
|
|
}
|
|
|
|
for (K = 0; K < f->numVerts; K++) {
|
|
if (K != S) {
|
|
NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
|
|
}
|
|
}
|
|
}
|
|
else if (y == 0) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no);
|
|
if (!yLimitNext || x < gridSize - 2) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no);
|
|
}
|
|
}
|
|
else if (x == 0) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no);
|
|
if (!xLimitPrev || y < gridSize - 2) {
|
|
NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcVertNormals_faces_finalize_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGFace *f = data->effectedF[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int lvl = ss->subdivLevels;
|
|
const int gridSize = ccg_gridsize(lvl);
|
|
const int normalDataOffset = ss->normalDataOffset;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
int S, x, y;
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1),
|
|
FACE_getIFNo(f, lvl, S, gridSize - 1, 0));
|
|
}
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
for (y = 0; y < gridSize; y++) {
|
|
for (x = 0; x < gridSize; x++) {
|
|
float *no = FACE_getIFNo(f, lvl, S, x, y);
|
|
Normalize(no);
|
|
}
|
|
}
|
|
|
|
VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset),
|
|
FACE_getIFNo(f, lvl, S, 0, 0),
|
|
ss);
|
|
|
|
for (x = 1; x < gridSize - 1; x++) {
|
|
NormCopy(FACE_getIENo(f, lvl, S, x), FACE_getIFNo(f, lvl, S, x, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGEdge *e = data->effectedE[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int lvl = ss->subdivLevels;
|
|
const int edgeSize = ccg_edgesize(lvl);
|
|
const int normalDataOffset = ss->normalDataOffset;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
if (e->numFaces) {
|
|
CCGFace *fLast = e->faces[e->numFaces - 1];
|
|
int x, i;
|
|
|
|
for (i = 0; i < e->numFaces - 1; i++) {
|
|
CCGFace *f = e->faces[i];
|
|
const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
|
|
const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
|
|
|
|
for (x = 1; x < edgeSize - 1; x++) {
|
|
NormAdd(
|
|
_face_getIFNoEdge(
|
|
fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
|
|
_face_getIFNoEdge(
|
|
f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < e->numFaces - 1; i++) {
|
|
CCGFace *f = e->faces[i];
|
|
const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
|
|
const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
|
|
|
|
for (x = 1; x < edgeSize - 1; x++) {
|
|
NormCopy(
|
|
_face_getIFNoEdge(
|
|
f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
|
|
_face_getIFNoEdge(
|
|
fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
|
|
CCGVert **effectedV,
|
|
CCGEdge **effectedE,
|
|
CCGFace **effectedF,
|
|
int numEffectedV,
|
|
int numEffectedE,
|
|
int numEffectedF)
|
|
{
|
|
int i, ptrIdx;
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int lvl = ss->subdivLevels;
|
|
const int edgeSize = ccg_edgesize(lvl);
|
|
const int gridSize = ccg_gridsize(lvl);
|
|
const int normalDataOffset = ss->normalDataOffset;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
CCGSubSurfCalcSubdivData data{};
|
|
data.ss = ss;
|
|
data.effectedV = effectedV;
|
|
data.effectedE = effectedE;
|
|
data.effectedF = effectedF;
|
|
data.numEffectedV = numEffectedV;
|
|
data.numEffectedE = numEffectedE;
|
|
data.numEffectedF = numEffectedF;
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(
|
|
0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings);
|
|
}
|
|
|
|
/* XXX can I reduce the number of normalization calls here? */
|
|
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
|
CCGVert *v = (CCGVert *)effectedV[ptrIdx];
|
|
float *no = VERT_getNo(v, lvl);
|
|
|
|
NormZero(no);
|
|
|
|
for (i = 0; i < v->numFaces; i++) {
|
|
CCGFace *f = v->faces[i];
|
|
NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1));
|
|
}
|
|
|
|
if (UNLIKELY(v->numFaces == 0)) {
|
|
NormCopy(no, VERT_getCo(v, lvl));
|
|
}
|
|
|
|
Normalize(no);
|
|
|
|
for (i = 0; i < v->numFaces; i++) {
|
|
CCGFace *f = v->faces[i];
|
|
NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no);
|
|
}
|
|
}
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(
|
|
0, numEffectedE, &data, ccgSubSurf__calcVertNormals_edges_accumulate_cb, &settings);
|
|
}
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(
|
|
0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_finalize_cb, &settings);
|
|
}
|
|
|
|
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
|
|
CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
|
|
|
|
if (e->numFaces) {
|
|
CCGFace *f = e->faces[0];
|
|
int x;
|
|
const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
|
|
|
|
for (x = 0; x < edgeSize; x++) {
|
|
NormCopy(EDGE_getNo(e, lvl, x),
|
|
_face_getIFNoEdge(
|
|
f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
|
|
}
|
|
}
|
|
else {
|
|
/* set to zero here otherwise the normals are uninitialized memory
|
|
* render: tests/animation/knight.blend with valgrind.
|
|
* we could be more clever and interpolate vertex normals but these are
|
|
* most likely not used so just zero out. */
|
|
int x;
|
|
|
|
for (x = 0; x < edgeSize; x++) {
|
|
float *no = EDGE_getNo(e, lvl, x);
|
|
NormCopy(no, EDGE_getCo(e, lvl, x));
|
|
Normalize(no);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGFace *f = data->effectedF[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int curLvl = data->curLvl;
|
|
const int nextLvl = curLvl + 1;
|
|
const int gridSize = ccg_gridsize(curLvl);
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
int S, x, y;
|
|
|
|
/* interior face midpoints
|
|
* - old interior face points
|
|
*/
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
for (y = 0; y < gridSize - 1; y++) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
int fx = 1 + 2 * x;
|
|
int fy = 1 + 2 * y;
|
|
const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0);
|
|
const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0);
|
|
const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1);
|
|
const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1);
|
|
float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3, ss);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* interior edge midpoints
|
|
* - old interior edge points
|
|
* - new interior face midpoints
|
|
*/
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
int fx = x * 2 + 1;
|
|
const float *co0 = FACE_getIECo(f, curLvl, S, x + 0);
|
|
const float *co1 = FACE_getIECo(f, curLvl, S, x + 1);
|
|
const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx);
|
|
const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
|
|
float *co = FACE_getIECo(f, nextLvl, S, fx);
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3, ss);
|
|
}
|
|
|
|
/* interior face interior edge midpoints
|
|
* - old interior face points
|
|
* - new interior face midpoints
|
|
*/
|
|
|
|
/* vertical */
|
|
for (x = 1; x < gridSize - 1; x++) {
|
|
for (y = 0; y < gridSize - 1; y++) {
|
|
int fx = x * 2;
|
|
int fy = y * 2 + 1;
|
|
const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0);
|
|
const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1);
|
|
const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy);
|
|
const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy);
|
|
float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3, ss);
|
|
}
|
|
}
|
|
|
|
/* horizontal */
|
|
for (y = 1; y < gridSize - 1; y++) {
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
int fx = x * 2 + 1;
|
|
int fy = y * 2;
|
|
const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y);
|
|
const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y);
|
|
const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1);
|
|
const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1);
|
|
float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
VertDataAvg4(co, co0, co1, co2, co3, ss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGFace *f = data->effectedF[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int curLvl = data->curLvl;
|
|
const int nextLvl = curLvl + 1;
|
|
const int gridSize = ccg_gridsize(curLvl);
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
float *q_thread = static_cast<float *>(alloca(vertDataSize));
|
|
float *r_thread = static_cast<float *>(alloca(vertDataSize));
|
|
|
|
int S, x, y;
|
|
|
|
/* interior center point shift
|
|
* - old face center point (shifting)
|
|
* - old interior edge points
|
|
* - new interior face midpoints
|
|
*/
|
|
VertDataZero(q_thread, ss);
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
|
|
}
|
|
VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
|
|
VertDataZero(r_thread, ss);
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
|
|
}
|
|
VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
|
|
|
|
VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
|
|
VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
|
|
VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
|
|
VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
/* interior face shift
|
|
* - old interior face point (shifting)
|
|
* - new interior edge midpoints
|
|
* - new interior face midpoints
|
|
*/
|
|
for (x = 1; x < gridSize - 1; x++) {
|
|
for (y = 1; y < gridSize - 1; y++) {
|
|
int fx = x * 2;
|
|
int fy = y * 2;
|
|
const float *co = FACE_getIFCo(f, curLvl, S, x, y);
|
|
float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
|
|
|
|
VertDataAvg4(q_thread,
|
|
FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
|
|
FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
|
|
ss);
|
|
|
|
VertDataAvg4(r_thread,
|
|
FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1),
|
|
ss);
|
|
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataSub(nCo, q_thread, ss);
|
|
VertDataMulN(nCo, 0.25f, ss);
|
|
VertDataAdd(nCo, r_thread, ss);
|
|
}
|
|
}
|
|
|
|
/* interior edge interior shift
|
|
* - old interior edge point (shifting)
|
|
* - new interior edge midpoints
|
|
* - new interior face midpoints
|
|
*/
|
|
for (x = 1; x < gridSize - 1; x++) {
|
|
int fx = x * 2;
|
|
const float *co = FACE_getIECo(f, curLvl, S, x);
|
|
float *nCo = FACE_getIECo(f, nextLvl, S, fx);
|
|
|
|
VertDataAvg4(q_thread,
|
|
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
|
|
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
|
|
FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
|
|
FACE_getIFCo(f, nextLvl, S, fx - 1, +1),
|
|
ss);
|
|
|
|
VertDataAvg4(r_thread,
|
|
FACE_getIECo(f, nextLvl, S, fx - 1),
|
|
FACE_getIECo(f, nextLvl, S, fx + 1),
|
|
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
|
|
FACE_getIFCo(f, nextLvl, S, fx, 1),
|
|
ss);
|
|
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataSub(nCo, q_thread, ss);
|
|
VertDataMulN(nCo, 0.25f, ss);
|
|
VertDataAdd(nCo, r_thread, ss);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(
|
|
void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
CCGSubSurfCalcSubdivData *data = static_cast<CCGSubSurfCalcSubdivData *>(userdata);
|
|
|
|
CCGSubSurf *ss = data->ss;
|
|
CCGFace *f = data->effectedF[ptrIdx];
|
|
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int nextLvl = data->curLvl + 1;
|
|
const int gridSize = ccg_gridsize(nextLvl);
|
|
const int cornerIdx = gridSize - 1;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
|
|
int S, x;
|
|
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx),
|
|
VERT_getCo(FACE_getVerts(f)[S], nextLvl),
|
|
ss);
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx),
|
|
EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx),
|
|
ss);
|
|
for (x = 1; x < gridSize - 1; x++) {
|
|
float *co = FACE_getIECo(f, nextLvl, S, x);
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss);
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss);
|
|
}
|
|
for (x = 0; x < gridSize - 1; x++) {
|
|
int eI = gridSize - 1 - x;
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x),
|
|
static_cast<const float *>(
|
|
_edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize)),
|
|
ss);
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx),
|
|
static_cast<const float *>(
|
|
_edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize)),
|
|
ss);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
|
|
CCGVert **effectedV,
|
|
CCGEdge **effectedE,
|
|
CCGFace **effectedF,
|
|
const int numEffectedV,
|
|
const int numEffectedE,
|
|
const int numEffectedF,
|
|
const int curLvl)
|
|
{
|
|
const int subdivLevels = ss->subdivLevels;
|
|
const int nextLvl = curLvl + 1;
|
|
int edgeSize = ccg_edgesize(curLvl);
|
|
int ptrIdx, i;
|
|
const int vertDataSize = ss->meshIFC.vertDataSize;
|
|
float *q = static_cast<float *>(ss->q), *r = static_cast<float *>(ss->r);
|
|
|
|
CCGSubSurfCalcSubdivData data{};
|
|
data.ss = ss;
|
|
data.effectedV = effectedV;
|
|
data.effectedE = effectedE;
|
|
data.effectedF = effectedF;
|
|
data.numEffectedV = numEffectedV;
|
|
data.numEffectedE = numEffectedE;
|
|
data.numEffectedF = numEffectedF;
|
|
data.curLvl = curLvl;
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(0,
|
|
numEffectedF,
|
|
&data,
|
|
ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
|
|
&settings);
|
|
}
|
|
|
|
/* exterior edge midpoints
|
|
* - old exterior edge points
|
|
* - new interior face midpoints
|
|
*/
|
|
/* Not worth parallelizing. */
|
|
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
|
|
CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
int x, j;
|
|
|
|
if (_edge_isBoundary(e) || sharpness > 1.0f) {
|
|
for (x = 0; x < edgeSize - 1; x++) {
|
|
int fx = x * 2 + 1;
|
|
const float *co0 = EDGE_getCo(e, curLvl, x + 0);
|
|
const float *co1 = EDGE_getCo(e, curLvl, x + 1);
|
|
float *co = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
VertDataCopy(co, co0, ss);
|
|
VertDataAdd(co, co1, ss);
|
|
VertDataMulN(co, 0.5f, ss);
|
|
}
|
|
}
|
|
else {
|
|
for (x = 0; x < edgeSize - 1; x++) {
|
|
int fx = x * 2 + 1;
|
|
const float *co0 = EDGE_getCo(e, curLvl, x + 0);
|
|
const float *co1 = EDGE_getCo(e, curLvl, x + 1);
|
|
float *co = EDGE_getCo(e, nextLvl, fx);
|
|
int numFaces = 0;
|
|
|
|
VertDataCopy(q, co0, ss);
|
|
VertDataAdd(q, co1, ss);
|
|
|
|
for (j = 0; j < e->numFaces; j++) {
|
|
CCGFace *f = e->faces[j];
|
|
const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
|
|
VertDataAdd(q,
|
|
static_cast<const float *>(ccg_face_getIFCoEdge(
|
|
f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize)),
|
|
ss);
|
|
numFaces++;
|
|
}
|
|
|
|
VertDataMulN(q, 1.0f / (2.0f + numFaces), ss);
|
|
|
|
VertDataCopy(r, co0, ss);
|
|
VertDataAdd(r, co1, ss);
|
|
VertDataMulN(r, 0.5f, ss);
|
|
|
|
VertDataCopy(co, q, ss);
|
|
VertDataSub(r, q, ss);
|
|
VertDataMulN(r, sharpness, ss);
|
|
VertDataAdd(co, r, ss);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* exterior vertex shift
|
|
* - old vertex points (shifting)
|
|
* - old exterior edge points
|
|
* - new interior face midpoints
|
|
*/
|
|
/* Not worth parallelizing. */
|
|
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
|
CCGVert *v = (CCGVert *)effectedV[ptrIdx];
|
|
const float *co = VERT_getCo(v, curLvl);
|
|
float *nCo = VERT_getCo(v, nextLvl);
|
|
int sharpCount = 0, allSharp = 1;
|
|
float avgSharpness = 0.0;
|
|
int j, seam = VERT_seam(v), seamEdges = 0;
|
|
|
|
for (j = 0; j < v->numEdges; j++) {
|
|
CCGEdge *e = v->edges[j];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
if (seam && _edge_isBoundary(e)) {
|
|
seamEdges++;
|
|
}
|
|
|
|
if (sharpness != 0.0f) {
|
|
sharpCount++;
|
|
avgSharpness += sharpness;
|
|
}
|
|
else {
|
|
allSharp = 0;
|
|
}
|
|
}
|
|
|
|
if (sharpCount) {
|
|
avgSharpness /= sharpCount;
|
|
if (avgSharpness > 1.0f) {
|
|
avgSharpness = 1.0f;
|
|
}
|
|
}
|
|
|
|
if (seamEdges < 2 || seamEdges != v->numEdges) {
|
|
seam = 0;
|
|
}
|
|
|
|
if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
|
|
VertDataCopy(nCo, co, ss);
|
|
}
|
|
else if (_vert_isBoundary(v)) {
|
|
int numBoundary = 0;
|
|
|
|
VertDataZero(r, ss);
|
|
for (j = 0; j < v->numEdges; j++) {
|
|
CCGEdge *e = v->edges[j];
|
|
if (_edge_isBoundary(e)) {
|
|
VertDataAdd(
|
|
r, static_cast<const float *>(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss);
|
|
numBoundary++;
|
|
}
|
|
}
|
|
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataMulN(nCo, 0.75f, ss);
|
|
VertDataMulN(r, 0.25f / numBoundary, ss);
|
|
VertDataAdd(nCo, r, ss);
|
|
}
|
|
else {
|
|
const int cornerIdx = (1 + (1 << (curLvl))) - 2;
|
|
int numEdges = 0, numFaces = 0;
|
|
|
|
VertDataZero(q, ss);
|
|
for (j = 0; j < v->numFaces; j++) {
|
|
CCGFace *f = v->faces[j];
|
|
VertDataAdd(
|
|
q, FACE_getIFCo(f, nextLvl, ccg_face_getVertIndex(f, v), cornerIdx, cornerIdx), ss);
|
|
numFaces++;
|
|
}
|
|
VertDataMulN(q, 1.0f / numFaces, ss);
|
|
VertDataZero(r, ss);
|
|
for (j = 0; j < v->numEdges; j++) {
|
|
CCGEdge *e = v->edges[j];
|
|
VertDataAdd(
|
|
r, static_cast<const float *>(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss);
|
|
numEdges++;
|
|
}
|
|
VertDataMulN(r, 1.0f / numEdges, ss);
|
|
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataMulN(nCo, numEdges - 2.0f, ss);
|
|
VertDataAdd(nCo, q, ss);
|
|
VertDataAdd(nCo, r, ss);
|
|
VertDataMulN(nCo, 1.0f / numEdges, ss);
|
|
}
|
|
|
|
if ((sharpCount > 1 && v->numFaces) || seam) {
|
|
VertDataZero(q, ss);
|
|
|
|
if (seam) {
|
|
avgSharpness = 1.0f;
|
|
sharpCount = seamEdges;
|
|
allSharp = 1;
|
|
}
|
|
|
|
for (j = 0; j < v->numEdges; j++) {
|
|
CCGEdge *e = v->edges[j];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
if (seam) {
|
|
if (_edge_isBoundary(e)) {
|
|
VertDataAdd(
|
|
q, static_cast<const float *>(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss);
|
|
}
|
|
}
|
|
else if (sharpness != 0.0f) {
|
|
VertDataAdd(
|
|
q, static_cast<const float *>(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss);
|
|
}
|
|
}
|
|
|
|
VertDataMulN(q, float(1) / sharpCount, ss);
|
|
|
|
if (sharpCount != 2 || allSharp) {
|
|
/* q = q + (co - q) * avgSharpness */
|
|
VertDataCopy(r, co, ss);
|
|
VertDataSub(r, q, ss);
|
|
VertDataMulN(r, avgSharpness, ss);
|
|
VertDataAdd(q, r, ss);
|
|
}
|
|
|
|
/* r = co * 0.75 + q * 0.25 */
|
|
VertDataCopy(r, co, ss);
|
|
VertDataMulN(r, 0.75f, ss);
|
|
VertDataMulN(q, 0.25f, ss);
|
|
VertDataAdd(r, q, ss);
|
|
|
|
/* nCo = nCo + (r - nCo) * avgSharpness */
|
|
VertDataSub(r, nCo, ss);
|
|
VertDataMulN(r, avgSharpness, ss);
|
|
VertDataAdd(nCo, r, ss);
|
|
}
|
|
}
|
|
|
|
/* exterior edge interior shift
|
|
* - old exterior edge midpoints (shifting)
|
|
* - old exterior edge midpoints
|
|
* - new interior face midpoints
|
|
*/
|
|
/* Not worth parallelizing. */
|
|
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
|
|
CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
int sharpCount = 0;
|
|
float avgSharpness = 0.0;
|
|
int x, j;
|
|
|
|
if (sharpness != 0.0f) {
|
|
sharpCount = 2;
|
|
avgSharpness += sharpness;
|
|
|
|
if (avgSharpness > 1.0f) {
|
|
avgSharpness = 1.0f;
|
|
}
|
|
}
|
|
else {
|
|
sharpCount = 0;
|
|
avgSharpness = 0;
|
|
}
|
|
|
|
if (_edge_isBoundary(e)) {
|
|
for (x = 1; x < edgeSize - 1; x++) {
|
|
int fx = x * 2;
|
|
const float *co = EDGE_getCo(e, curLvl, x);
|
|
float *nCo = EDGE_getCo(e, nextLvl, fx);
|
|
|
|
/* Average previous level's endpoints */
|
|
VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss);
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
|
|
VertDataMulN(r, 0.5f, ss);
|
|
|
|
/* nCo = nCo * 0.75 + r * 0.25 */
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataMulN(nCo, 0.75f, ss);
|
|
VertDataMulN(r, 0.25f, ss);
|
|
VertDataAdd(nCo, r, ss);
|
|
}
|
|
}
|
|
else {
|
|
for (x = 1; x < edgeSize - 1; x++) {
|
|
int fx = x * 2;
|
|
const float *co = EDGE_getCo(e, curLvl, x);
|
|
float *nCo = EDGE_getCo(e, nextLvl, fx);
|
|
int numFaces = 0;
|
|
|
|
VertDataZero(q, ss);
|
|
VertDataZero(r, ss);
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss);
|
|
VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
|
|
for (j = 0; j < e->numFaces; j++) {
|
|
CCGFace *f = e->faces[j];
|
|
int f_ed_idx = ccg_face_getEdgeIndex(f, e);
|
|
VertDataAdd(q,
|
|
static_cast<const float *>(ccg_face_getIFCoEdge(
|
|
f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize)),
|
|
ss);
|
|
VertDataAdd(q,
|
|
static_cast<const float *>(ccg_face_getIFCoEdge(
|
|
f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize)),
|
|
ss);
|
|
|
|
VertDataAdd(r,
|
|
static_cast<const float *>(ccg_face_getIFCoEdge(
|
|
f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize)),
|
|
ss);
|
|
numFaces++;
|
|
}
|
|
VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss);
|
|
VertDataMulN(r, 1.0f / (2.0f + numFaces), ss);
|
|
|
|
VertDataCopy(nCo, co, ss);
|
|
VertDataMulN(nCo, float(numFaces), ss);
|
|
VertDataAdd(nCo, q, ss);
|
|
VertDataAdd(nCo, r, ss);
|
|
VertDataMulN(nCo, 1.0f / (2 + numFaces), ss);
|
|
|
|
if (sharpCount == 2) {
|
|
VertDataCopy(q, co, ss);
|
|
VertDataMulN(q, 6.0f, ss);
|
|
VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss);
|
|
VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss);
|
|
VertDataMulN(q, 1 / 8.0f, ss);
|
|
|
|
VertDataSub(q, nCo, ss);
|
|
VertDataMulN(q, avgSharpness, ss);
|
|
VertDataAdd(nCo, q, ss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(0,
|
|
numEffectedF,
|
|
&data,
|
|
ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
|
|
&settings);
|
|
}
|
|
|
|
/* copy down */
|
|
edgeSize = ccg_edgesize(nextLvl);
|
|
|
|
/* Not worth parallelizing. */
|
|
for (i = 0; i < numEffectedE; i++) {
|
|
CCGEdge *e = effectedE[i];
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss);
|
|
}
|
|
|
|
{
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
BLI_task_parallel_range(
|
|
0, numEffectedF, &data, ccgSubSurf__calcSubdivLevel_verts_copydata_cb, &settings);
|
|
}
|
|
}
|
|
|
|
void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
|
|
{
|
|
CCGVert **effectedV;
|
|
CCGEdge **effectedE;
|
|
CCGFace **effectedF;
|
|
int numEffectedV, numEffectedE, numEffectedF;
|
|
int subdivLevels = ss->subdivLevels;
|
|
int vertDataSize = ss->meshIFC.vertDataSize;
|
|
int i, j, ptrIdx, S;
|
|
int curLvl, nextLvl;
|
|
void *q = ss->q, *r = ss->r;
|
|
|
|
effectedV = static_cast<CCGVert **>(
|
|
MEM_mallocN(sizeof(*effectedV) * ss->vMap->numEntries, "CCGSubsurf effectedV"));
|
|
effectedE = static_cast<CCGEdge **>(
|
|
MEM_mallocN(sizeof(*effectedE) * ss->eMap->numEntries, "CCGSubsurf effectedE"));
|
|
effectedF = static_cast<CCGFace **>(
|
|
MEM_mallocN(sizeof(*effectedF) * ss->fMap->numEntries, "CCGSubsurf effectedF"));
|
|
numEffectedV = numEffectedE = numEffectedF = 0;
|
|
for (i = 0; i < ss->vMap->curSize; i++) {
|
|
CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
|
|
for (; v; v = v->next) {
|
|
if (v->flags & Vert_eEffected) {
|
|
effectedV[numEffectedV++] = v;
|
|
|
|
for (j = 0; j < v->numEdges; j++) {
|
|
CCGEdge *e = v->edges[j];
|
|
if (!(e->flags & Edge_eEffected)) {
|
|
effectedE[numEffectedE++] = e;
|
|
e->flags |= Edge_eEffected;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < v->numFaces; j++) {
|
|
CCGFace *f = v->faces[j];
|
|
if (!(f->flags & Face_eEffected)) {
|
|
effectedF[numEffectedF++] = f;
|
|
f->flags |= Face_eEffected;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
curLvl = 0;
|
|
nextLvl = curLvl + 1;
|
|
|
|
for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
|
|
CCGFace *f = effectedF[ptrIdx];
|
|
void *co = FACE_getCenterData(f);
|
|
VertDataZero(static_cast<float *>(co), ss);
|
|
for (i = 0; i < f->numVerts; i++) {
|
|
VertDataAdd(static_cast<float *>(co), VERT_getCo(FACE_getVerts(f)[i], curLvl), ss);
|
|
}
|
|
VertDataMulN(static_cast<float *>(co), 1.0f / f->numVerts, ss);
|
|
|
|
f->flags = 0;
|
|
}
|
|
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
|
|
CCGEdge *e = effectedE[ptrIdx];
|
|
void *co = EDGE_getCo(e, nextLvl, 1);
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
if (_edge_isBoundary(e) || sharpness >= 1.0f) {
|
|
VertDataCopy(static_cast<float *>(co), VERT_getCo(e->v0, curLvl), ss);
|
|
VertDataAdd(static_cast<float *>(co), VERT_getCo(e->v1, curLvl), ss);
|
|
VertDataMulN(static_cast<float *>(co), 0.5f, ss);
|
|
}
|
|
else {
|
|
int numFaces = 0;
|
|
VertDataCopy(static_cast<float *>(q), VERT_getCo(e->v0, curLvl), ss);
|
|
VertDataAdd(static_cast<float *>(q), VERT_getCo(e->v1, curLvl), ss);
|
|
for (i = 0; i < e->numFaces; i++) {
|
|
CCGFace *f = e->faces[i];
|
|
VertDataAdd(static_cast<float *>(q), (float *)FACE_getCenterData(f), ss);
|
|
numFaces++;
|
|
}
|
|
VertDataMulN(static_cast<float *>(q), 1.0f / (2.0f + numFaces), ss);
|
|
|
|
VertDataCopy(static_cast<float *>(r), VERT_getCo(e->v0, curLvl), ss);
|
|
VertDataAdd(static_cast<float *>(r), VERT_getCo(e->v1, curLvl), ss);
|
|
VertDataMulN(static_cast<float *>(r), 0.5f, ss);
|
|
|
|
VertDataCopy(static_cast<float *>(co), static_cast<const float *>(q), ss);
|
|
VertDataSub(static_cast<float *>(r), static_cast<const float *>(q), ss);
|
|
VertDataMulN(static_cast<float *>(r), sharpness, ss);
|
|
VertDataAdd(static_cast<float *>(co), static_cast<const float *>(r), ss);
|
|
}
|
|
|
|
/* edge flags cleared later */
|
|
}
|
|
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
|
CCGVert *v = effectedV[ptrIdx];
|
|
void *co = VERT_getCo(v, curLvl);
|
|
void *nCo = VERT_getCo(v, nextLvl);
|
|
int sharpCount = 0, allSharp = 1;
|
|
float avgSharpness = 0.0;
|
|
int seam = VERT_seam(v), seamEdges = 0;
|
|
|
|
for (i = 0; i < v->numEdges; i++) {
|
|
CCGEdge *e = v->edges[i];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
if (seam && _edge_isBoundary(e)) {
|
|
seamEdges++;
|
|
}
|
|
|
|
if (sharpness != 0.0f) {
|
|
sharpCount++;
|
|
avgSharpness += sharpness;
|
|
}
|
|
else {
|
|
allSharp = 0;
|
|
}
|
|
}
|
|
|
|
if (sharpCount) {
|
|
avgSharpness /= sharpCount;
|
|
if (avgSharpness > 1.0f) {
|
|
avgSharpness = 1.0f;
|
|
}
|
|
}
|
|
|
|
if (seamEdges < 2 || seamEdges != v->numEdges) {
|
|
seam = 0;
|
|
}
|
|
|
|
if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
|
|
VertDataCopy(static_cast<float *>(nCo), static_cast<const float *>(co), ss);
|
|
}
|
|
else if (_vert_isBoundary(v)) {
|
|
int numBoundary = 0;
|
|
|
|
VertDataZero(static_cast<float *>(r), ss);
|
|
for (i = 0; i < v->numEdges; i++) {
|
|
CCGEdge *e = v->edges[i];
|
|
if (_edge_isBoundary(e)) {
|
|
VertDataAdd(static_cast<float *>(r), VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
|
|
numBoundary++;
|
|
}
|
|
}
|
|
VertDataCopy(static_cast<float *>(nCo), static_cast<const float *>(co), ss);
|
|
VertDataMulN(static_cast<float *>(nCo), 0.75f, ss);
|
|
VertDataMulN(static_cast<float *>(r), 0.25f / numBoundary, ss);
|
|
VertDataAdd(static_cast<float *>(nCo), static_cast<const float *>(r), ss);
|
|
}
|
|
else {
|
|
int numEdges = 0, numFaces = 0;
|
|
|
|
VertDataZero(static_cast<float *>(q), ss);
|
|
for (i = 0; i < v->numFaces; i++) {
|
|
CCGFace *f = v->faces[i];
|
|
VertDataAdd(static_cast<float *>(q), (float *)FACE_getCenterData(f), ss);
|
|
numFaces++;
|
|
}
|
|
VertDataMulN(static_cast<float *>(q), 1.0f / numFaces, ss);
|
|
VertDataZero(static_cast<float *>(r), ss);
|
|
for (i = 0; i < v->numEdges; i++) {
|
|
CCGEdge *e = v->edges[i];
|
|
VertDataAdd(static_cast<float *>(r), VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
|
|
numEdges++;
|
|
}
|
|
VertDataMulN(static_cast<float *>(r), 1.0f / numEdges, ss);
|
|
|
|
VertDataCopy(static_cast<float *>(nCo), static_cast<const float *>(co), ss);
|
|
VertDataMulN(static_cast<float *>(nCo), numEdges - 2.0f, ss);
|
|
VertDataAdd(static_cast<float *>(nCo), static_cast<const float *>(q), ss);
|
|
VertDataAdd(static_cast<float *>(nCo), static_cast<const float *>(r), ss);
|
|
VertDataMulN(static_cast<float *>(nCo), 1.0f / numEdges, ss);
|
|
}
|
|
|
|
if (sharpCount > 1 || seam) {
|
|
VertDataZero(static_cast<float *>(q), ss);
|
|
|
|
if (seam) {
|
|
avgSharpness = 1.0f;
|
|
sharpCount = seamEdges;
|
|
allSharp = 1;
|
|
}
|
|
|
|
for (i = 0; i < v->numEdges; i++) {
|
|
CCGEdge *e = v->edges[i];
|
|
float sharpness = EDGE_getSharpness(e, curLvl);
|
|
|
|
if (seam) {
|
|
if (_edge_isBoundary(e)) {
|
|
CCGVert *oV = _edge_getOtherVert(e, v);
|
|
VertDataAdd(static_cast<float *>(q), VERT_getCo(oV, curLvl), ss);
|
|
}
|
|
}
|
|
else if (sharpness != 0.0f) {
|
|
CCGVert *oV = _edge_getOtherVert(e, v);
|
|
VertDataAdd(static_cast<float *>(q), VERT_getCo(oV, curLvl), ss);
|
|
}
|
|
}
|
|
|
|
VertDataMulN(static_cast<float *>(q), float(1) / sharpCount, ss);
|
|
|
|
if (sharpCount != 2 || allSharp) {
|
|
/* q = q + (co - q) * avgSharpness */
|
|
VertDataCopy(static_cast<float *>(r), static_cast<const float *>(co), ss);
|
|
VertDataSub(static_cast<float *>(r), static_cast<const float *>(q), ss);
|
|
VertDataMulN(static_cast<float *>(r), avgSharpness, ss);
|
|
VertDataAdd(static_cast<float *>(q), static_cast<const float *>(r), ss);
|
|
}
|
|
|
|
/* r = co * 0.75 + q * 0.25 */
|
|
VertDataCopy(static_cast<float *>(r), static_cast<const float *>(co), ss);
|
|
VertDataMulN(static_cast<float *>(r), 0.75f, ss);
|
|
VertDataMulN(static_cast<float *>(q), 0.25f, ss);
|
|
VertDataAdd(static_cast<float *>(r), static_cast<const float *>(q), ss);
|
|
|
|
/* nCo = nCo + (r - nCo) * avgSharpness */
|
|
VertDataSub(static_cast<float *>(r), static_cast<const float *>(nCo), ss);
|
|
VertDataMulN(static_cast<float *>(r), avgSharpness, ss);
|
|
VertDataAdd(static_cast<float *>(nCo), static_cast<const float *>(r), ss);
|
|
}
|
|
|
|
/* vert flags cleared later */
|
|
}
|
|
|
|
if (ss->useAgeCounts) {
|
|
for (i = 0; i < numEffectedV; i++) {
|
|
CCGVert *v = effectedV[i];
|
|
byte *user_data = static_cast<byte *>(ccgSubSurf_getVertUserData(ss, v));
|
|
*((int *)&user_data[ss->vertUserAgeOffset]) = ss->currentAge;
|
|
}
|
|
|
|
for (i = 0; i < numEffectedE; i++) {
|
|
CCGEdge *e = effectedE[i];
|
|
byte *user_data = static_cast<byte *>(ccgSubSurf_getEdgeUserData(ss, e));
|
|
*((int *)&user_data[ss->edgeUserAgeOffset]) = ss->currentAge;
|
|
}
|
|
|
|
for (i = 0; i < numEffectedF; i++) {
|
|
CCGFace *f = effectedF[i];
|
|
byte *user_data = static_cast<byte *>(ccgSubSurf_getFaceUserData(ss, f));
|
|
*((int *)&user_data[ss->faceUserAgeOffset]) = ss->currentAge;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < numEffectedE; i++) {
|
|
CCGEdge *e = effectedE[i];
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
|
|
VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss);
|
|
}
|
|
for (i = 0; i < numEffectedF; i++) {
|
|
CCGFace *f = effectedF[i];
|
|
for (S = 0; S < f->numVerts; S++) {
|
|
CCGEdge *e = FACE_getEdges(f)[S];
|
|
CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
|
|
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
|
|
VertDataCopy(
|
|
FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
|
|
VertDataCopy(
|
|
FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss);
|
|
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0),
|
|
static_cast<const float *>(
|
|
_edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)),
|
|
ss);
|
|
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1),
|
|
static_cast<const float *>(
|
|
_edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)),
|
|
ss);
|
|
}
|
|
}
|
|
|
|
for (curLvl = 1; curLvl < subdivLevels; curLvl++) {
|
|
ccgSubSurf__calcSubdivLevel(
|
|
ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl);
|
|
}
|
|
|
|
if (ss->calcVertNormals) {
|
|
ccgSubSurf__calcVertNormals(
|
|
ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF);
|
|
}
|
|
|
|
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
|
|
CCGVert *v = effectedV[ptrIdx];
|
|
v->flags = 0;
|
|
}
|
|
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
|
|
CCGEdge *e = effectedE[ptrIdx];
|
|
e->flags = 0;
|
|
}
|
|
|
|
MEM_freeN(effectedF);
|
|
MEM_freeN(effectedE);
|
|
MEM_freeN(effectedV);
|
|
|
|
#ifdef DUMP_RESULT_GRIDS
|
|
ccgSubSurf__dumpCoords(ss);
|
|
#endif
|
|
}
|
|
|
|
/* ** Public API exposed to other areas which depends on old CCG code. ** */
|
|
|
|
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF)
|
|
{
|
|
CCGVert **effectedV;
|
|
CCGEdge **effectedE;
|
|
int i, numEffectedV, numEffectedE, freeF;
|
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
ccgSubSurf__effectedFaceNeighbors(
|
|
ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
|
|
|
if (ss->calcVertNormals) {
|
|
ccgSubSurf__calcVertNormals(
|
|
ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF);
|
|
}
|
|
|
|
for (i = 0; i < numEffectedV; i++) {
|
|
effectedV[i]->flags = 0;
|
|
}
|
|
for (i = 0; i < numEffectedE; i++) {
|
|
effectedE[i]->flags = 0;
|
|
}
|
|
for (i = 0; i < numEffectedF; i++) {
|
|
effectedF[i]->flags = 0;
|
|
}
|
|
|
|
MEM_freeN(effectedE);
|
|
MEM_freeN(effectedV);
|
|
if (freeF) {
|
|
MEM_freeN(effectedF);
|
|
}
|
|
|
|
return eCCGError_None;
|
|
}
|
|
|
|
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
|
|
{
|
|
CCGVert **effectedV;
|
|
CCGEdge **effectedE;
|
|
int numEffectedV, numEffectedE, freeF, i;
|
|
int curLvl, subdivLevels = ss->subdivLevels;
|
|
|
|
ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
|
|
ccgSubSurf__effectedFaceNeighbors(
|
|
ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
|
|
|
|
for (curLvl = lvl; curLvl < subdivLevels; curLvl++) {
|
|
ccgSubSurf__calcSubdivLevel(
|
|
ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl);
|
|
}
|
|
|
|
for (i = 0; i < numEffectedV; i++) {
|
|
effectedV[i]->flags = 0;
|
|
}
|
|
for (i = 0; i < numEffectedE; i++) {
|
|
effectedE[i]->flags = 0;
|
|
}
|
|
for (i = 0; i < numEffectedF; i++) {
|
|
effectedF[i]->flags = 0;
|
|
}
|
|
|
|
MEM_freeN(effectedE);
|
|
MEM_freeN(effectedV);
|
|
if (freeF) {
|
|
MEM_freeN(effectedF);
|
|
}
|
|
|
|
return eCCGError_None;
|
|
}
|