|
|
|
|
@@ -44,6 +44,7 @@
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
#include "BLI_task.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_pbvh.h"
|
|
|
|
|
#include "BKE_ccg.h"
|
|
|
|
|
@@ -1002,6 +1003,117 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key,
|
|
|
|
|
copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct MultiresThreadedData {
|
|
|
|
|
DispOp op;
|
|
|
|
|
CCGElem **gridData, **subGridData;
|
|
|
|
|
CCGKey *key;
|
|
|
|
|
CCGKey *sub_key;
|
|
|
|
|
MPoly *mpoly;
|
|
|
|
|
MDisps *mdisps;
|
|
|
|
|
GridPaintMask *grid_paint_mask;
|
|
|
|
|
int *gridOffset;
|
|
|
|
|
int gridSize, dGridSize, dSkip;
|
|
|
|
|
float (*smat)[3];
|
|
|
|
|
} MultiresThreadedData;
|
|
|
|
|
|
|
|
|
|
static void multires_disp_run_cb(
|
|
|
|
|
void *__restrict userdata,
|
|
|
|
|
const int pidx,
|
|
|
|
|
const ParallelRangeTLS *__restrict UNUSED(tls))
|
|
|
|
|
{
|
|
|
|
|
MultiresThreadedData *tdata = userdata;
|
|
|
|
|
|
|
|
|
|
DispOp op = tdata->op;
|
|
|
|
|
CCGElem **gridData = tdata->gridData;
|
|
|
|
|
CCGElem **subGridData = tdata->subGridData;
|
|
|
|
|
CCGKey *key = tdata->key;
|
|
|
|
|
MPoly *mpoly = tdata->mpoly;
|
|
|
|
|
MDisps *mdisps = tdata->mdisps;
|
|
|
|
|
GridPaintMask *grid_paint_mask = tdata->grid_paint_mask;
|
|
|
|
|
int *gridOffset = tdata->gridOffset;
|
|
|
|
|
int gridSize = tdata->gridSize;
|
|
|
|
|
int dGridSize = tdata->dGridSize;
|
|
|
|
|
int dSkip = tdata->dSkip;
|
|
|
|
|
|
|
|
|
|
const int numVerts = mpoly[pidx].totloop;
|
|
|
|
|
int S, x, y, gIndex = gridOffset[pidx];
|
|
|
|
|
|
|
|
|
|
for (S = 0; S < numVerts; ++S, ++gIndex) {
|
|
|
|
|
GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
|
|
|
|
|
MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
|
|
|
|
|
CCGElem *grid = gridData[gIndex];
|
|
|
|
|
CCGElem *subgrid = subGridData[gIndex];
|
|
|
|
|
float (*dispgrid)[3] = NULL;
|
|
|
|
|
|
|
|
|
|
dispgrid = mdisp->disps;
|
|
|
|
|
|
|
|
|
|
/* if needed, reallocate multires paint mask */
|
|
|
|
|
if (gpm && gpm->level < key->level) {
|
|
|
|
|
gpm->level = key->level;
|
|
|
|
|
if (gpm->data) {
|
|
|
|
|
MEM_freeN(gpm->data);
|
|
|
|
|
}
|
|
|
|
|
gpm->data = MEM_callocN(sizeof(float) * key->grid_area, "gpm.data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (y = 0; y < gridSize; y++) {
|
|
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
|
float *co = CCG_grid_elem_co(key, grid, x, y);
|
|
|
|
|
float *sco = CCG_grid_elem_co(key, subgrid, x, y);
|
|
|
|
|
float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
|
|
|
|
|
float mat[3][3], disp[3], d[3], mask;
|
|
|
|
|
|
|
|
|
|
/* construct tangent space matrix */
|
|
|
|
|
grid_tangent_matrix(mat, key, x, y, subgrid);
|
|
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
|
case APPLY_DISPLACEMENTS:
|
|
|
|
|
/* Convert displacement to object space
|
|
|
|
|
* and add to grid points */
|
|
|
|
|
mul_v3_m3v3(disp, mat, data);
|
|
|
|
|
add_v3_v3v3(co, sco, disp);
|
|
|
|
|
break;
|
|
|
|
|
case CALC_DISPLACEMENTS:
|
|
|
|
|
/* Calculate displacement between new and old
|
|
|
|
|
* grid points and convert to tangent space */
|
|
|
|
|
sub_v3_v3v3(disp, co, sco);
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(data, mat, disp);
|
|
|
|
|
break;
|
|
|
|
|
case ADD_DISPLACEMENTS:
|
|
|
|
|
/* Convert subdivided displacements to tangent
|
|
|
|
|
* space and add to the original displacements */
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(d, mat, co);
|
|
|
|
|
add_v3_v3(data, d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gpm) {
|
|
|
|
|
switch (op) {
|
|
|
|
|
case APPLY_DISPLACEMENTS:
|
|
|
|
|
/* Copy mask from gpm to DM */
|
|
|
|
|
*CCG_grid_elem_mask(key, grid, x, y) =
|
|
|
|
|
paint_grid_paint_mask(gpm, key->level, x, y);
|
|
|
|
|
break;
|
|
|
|
|
case CALC_DISPLACEMENTS:
|
|
|
|
|
/* Copy mask from DM to gpm */
|
|
|
|
|
mask = *CCG_grid_elem_mask(key, grid, x, y);
|
|
|
|
|
gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
|
|
|
|
|
break;
|
|
|
|
|
case ADD_DISPLACEMENTS:
|
|
|
|
|
/* Add mask displacement to gpm */
|
|
|
|
|
gpm->data[y * gridSize + x] +=
|
|
|
|
|
*CCG_grid_elem_mask(key, grid, x, y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size),
|
|
|
|
|
* because this code uses CCGKey's info from dm to access oldGridData's normals
|
|
|
|
|
* (through the call to grid_tangent_matrix())! */
|
|
|
|
|
@@ -1014,7 +1126,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
|
|
|
|
|
MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
|
|
|
|
|
GridPaintMask *grid_paint_mask = NULL;
|
|
|
|
|
int *gridOffset;
|
|
|
|
|
int i, k, /*numGrids, */ gridSize, dGridSize, dSkip;
|
|
|
|
|
int i, gridSize, dGridSize, dSkip;
|
|
|
|
|
int totloop, totpoly;
|
|
|
|
|
|
|
|
|
|
/* this happens in the dm made by bmesh_mdisps_space_set */
|
|
|
|
|
@@ -1050,97 +1162,33 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
|
|
|
|
|
if (key.has_mask)
|
|
|
|
|
grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
|
|
|
|
|
|
|
|
|
|
k = 0; /*current loop/mdisp index within the mloop array*/
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for private(i) if (totloop * gridSize * gridSize >= CCG_OMP_LIMIT)
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < totpoly; ++i) {
|
|
|
|
|
const int numVerts = mpoly[i].totloop;
|
|
|
|
|
int S, x, y, gIndex = gridOffset[i];
|
|
|
|
|
|
|
|
|
|
for (S = 0; S < numVerts; ++S, ++gIndex, ++k) {
|
|
|
|
|
GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
|
|
|
|
|
MDisps *mdisp = &mdisps[mpoly[i].loopstart + S];
|
|
|
|
|
CCGElem *grid = gridData[gIndex];
|
|
|
|
|
CCGElem *subgrid = subGridData[gIndex];
|
|
|
|
|
float (*dispgrid)[3] = NULL;
|
|
|
|
|
|
|
|
|
|
/* when adding new faces in edit mode, need to allocate disps */
|
|
|
|
|
if (!mdisp->disps)
|
|
|
|
|
#pragma omp critical
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < totloop; ++i) {
|
|
|
|
|
if (mdisps[i].disps == NULL) {
|
|
|
|
|
multires_reallocate_mdisps(totloop, mdisps, totlvl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dispgrid = mdisp->disps;
|
|
|
|
|
|
|
|
|
|
/* if needed, reallocate multires paint mask */
|
|
|
|
|
if (gpm && gpm->level < key.level) {
|
|
|
|
|
gpm->level = key.level;
|
|
|
|
|
#pragma omp critical
|
|
|
|
|
{
|
|
|
|
|
if (gpm->data)
|
|
|
|
|
MEM_freeN(gpm->data);
|
|
|
|
|
gpm->data = MEM_callocN(sizeof(float) * key.grid_area, "gpm.data");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (y = 0; y < gridSize; y++) {
|
|
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
|
float *co = CCG_grid_elem_co(&key, grid, x, y);
|
|
|
|
|
float *sco = CCG_grid_elem_co(&key, subgrid, x, y);
|
|
|
|
|
float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
|
|
|
|
|
float mat[3][3], disp[3], d[3], mask;
|
|
|
|
|
|
|
|
|
|
/* construct tangent space matrix */
|
|
|
|
|
grid_tangent_matrix(mat, &key, x, y, subgrid);
|
|
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
|
case APPLY_DISPLACEMENTS:
|
|
|
|
|
/* Convert displacement to object space
|
|
|
|
|
* and add to grid points */
|
|
|
|
|
mul_v3_m3v3(disp, mat, data);
|
|
|
|
|
add_v3_v3v3(co, sco, disp);
|
|
|
|
|
break;
|
|
|
|
|
case CALC_DISPLACEMENTS:
|
|
|
|
|
/* Calculate displacement between new and old
|
|
|
|
|
* grid points and convert to tangent space */
|
|
|
|
|
sub_v3_v3v3(disp, co, sco);
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(data, mat, disp);
|
|
|
|
|
break;
|
|
|
|
|
case ADD_DISPLACEMENTS:
|
|
|
|
|
/* Convert subdivided displacements to tangent
|
|
|
|
|
* space and add to the original displacements */
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(d, mat, co);
|
|
|
|
|
add_v3_v3(data, d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gpm) {
|
|
|
|
|
switch (op) {
|
|
|
|
|
case APPLY_DISPLACEMENTS:
|
|
|
|
|
/* Copy mask from gpm to DM */
|
|
|
|
|
*CCG_grid_elem_mask(&key, grid, x, y) =
|
|
|
|
|
paint_grid_paint_mask(gpm, key.level, x, y);
|
|
|
|
|
break;
|
|
|
|
|
case CALC_DISPLACEMENTS:
|
|
|
|
|
/* Copy mask from DM to gpm */
|
|
|
|
|
mask = *CCG_grid_elem_mask(&key, grid, x, y);
|
|
|
|
|
gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
|
|
|
|
|
break;
|
|
|
|
|
case ADD_DISPLACEMENTS:
|
|
|
|
|
/* Add mask displacement to gpm */
|
|
|
|
|
gpm->data[y * gridSize + x] +=
|
|
|
|
|
*CCG_grid_elem_mask(&key, grid, x, y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ParallelRangeSettings settings;
|
|
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
|
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
|
|
|
|
|
|
|
|
MultiresThreadedData data = {
|
|
|
|
|
.op = op,
|
|
|
|
|
.gridData = gridData,
|
|
|
|
|
.subGridData = subGridData,
|
|
|
|
|
.key = &key,
|
|
|
|
|
.mpoly = mpoly,
|
|
|
|
|
.mdisps = mdisps,
|
|
|
|
|
.grid_paint_mask = grid_paint_mask,
|
|
|
|
|
.gridOffset = gridOffset,
|
|
|
|
|
.gridSize = gridSize,
|
|
|
|
|
.dGridSize = dGridSize,
|
|
|
|
|
.dSkip = dSkip
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings);
|
|
|
|
|
|
|
|
|
|
if (op == APPLY_DISPLACEMENTS) {
|
|
|
|
|
ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
|
|
|
|
|
@@ -1332,8 +1380,7 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
|
|
|
|
|
|
|
|
|
|
k = 0; /*current loop/mdisp index within the mloop array*/
|
|
|
|
|
|
|
|
|
|
//#pragma omp parallel for private(i) if (dm->numLoopData * gridSize * gridSize >= CCG_OMP_LIMIT)
|
|
|
|
|
|
|
|
|
|
/* TODO: Use BLI_task parallel range for that one too? */
|
|
|
|
|
for (i = 0; i < dm->numPolyData; ++i) {
|
|
|
|
|
const int numVerts = mpoly[i].totloop;
|
|
|
|
|
int S, x, y, gIndex = gridOffset[i];
|
|
|
|
|
@@ -2174,6 +2221,56 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void multires_apply_smat_cb(
|
|
|
|
|
void *__restrict userdata,
|
|
|
|
|
const int pidx,
|
|
|
|
|
const ParallelRangeTLS *__restrict UNUSED(tls))
|
|
|
|
|
{
|
|
|
|
|
MultiresThreadedData *tdata = userdata;
|
|
|
|
|
|
|
|
|
|
CCGElem **gridData = tdata->gridData;
|
|
|
|
|
CCGElem **subGridData = tdata->subGridData;
|
|
|
|
|
CCGKey *dm_key = tdata->key;
|
|
|
|
|
CCGKey *subdm_key = tdata->sub_key;
|
|
|
|
|
MPoly *mpoly = tdata->mpoly;
|
|
|
|
|
MDisps *mdisps = tdata->mdisps;
|
|
|
|
|
int *gridOffset = tdata->gridOffset;
|
|
|
|
|
int gridSize = tdata->gridSize;
|
|
|
|
|
int dGridSize = tdata->dGridSize;
|
|
|
|
|
int dSkip = tdata->dSkip;
|
|
|
|
|
float (*smat)[3] = tdata->smat;
|
|
|
|
|
|
|
|
|
|
const int numVerts = mpoly[pidx].totloop;
|
|
|
|
|
MDisps *mdisp = &mdisps[mpoly[pidx].loopstart];
|
|
|
|
|
int S, x, y, gIndex = gridOffset[pidx];
|
|
|
|
|
|
|
|
|
|
for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
|
|
|
|
|
CCGElem *grid = gridData[gIndex];
|
|
|
|
|
CCGElem *subgrid = subGridData[gIndex];
|
|
|
|
|
float (*dispgrid)[3] = mdisp->disps;
|
|
|
|
|
|
|
|
|
|
for (y = 0; y < gridSize; y++) {
|
|
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
|
float *co = CCG_grid_elem_co(dm_key, grid, x, y);
|
|
|
|
|
float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y);
|
|
|
|
|
float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
|
|
|
|
|
float mat[3][3], disp[3];
|
|
|
|
|
|
|
|
|
|
/* construct tangent space matrix */
|
|
|
|
|
grid_tangent_matrix(mat, dm_key, x, y, grid);
|
|
|
|
|
|
|
|
|
|
/* scale subgrid coord and calculate displacement */
|
|
|
|
|
mul_m3_v3(smat, sco);
|
|
|
|
|
sub_v3_v3v3(disp, sco, co);
|
|
|
|
|
|
|
|
|
|
/* convert difference to tangent space */
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(data, mat, disp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, float smat[3][3])
|
|
|
|
|
{
|
|
|
|
|
DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL;
|
|
|
|
|
@@ -2226,38 +2323,25 @@ static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene
|
|
|
|
|
dGridSize = multires_side_tot[high_mmd.totlvl];
|
|
|
|
|
dSkip = (dGridSize - 1) / (gridSize - 1);
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for private(i) if (me->totloop * gridSize * gridSize >= CCG_OMP_LIMIT)
|
|
|
|
|
for (i = 0; i < me->totpoly; ++i) {
|
|
|
|
|
const int numVerts = mpoly[i].totloop;
|
|
|
|
|
MDisps *mdisp = &mdisps[mpoly[i].loopstart];
|
|
|
|
|
int S, x, y, gIndex = gridOffset[i];
|
|
|
|
|
ParallelRangeSettings settings;
|
|
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
|
|
|
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
|
|
|
|
|
|
|
|
|
for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
|
|
|
|
|
CCGElem *grid = gridData[gIndex];
|
|
|
|
|
CCGElem *subgrid = subGridData[gIndex];
|
|
|
|
|
float (*dispgrid)[3] = mdisp->disps;
|
|
|
|
|
MultiresThreadedData data = {
|
|
|
|
|
.gridData = gridData,
|
|
|
|
|
.subGridData = subGridData,
|
|
|
|
|
.key = &dm_key,
|
|
|
|
|
.sub_key = &subdm_key,
|
|
|
|
|
.mpoly = mpoly,
|
|
|
|
|
.mdisps = mdisps,
|
|
|
|
|
.gridOffset = gridOffset,
|
|
|
|
|
.gridSize = gridSize,
|
|
|
|
|
.dGridSize = dGridSize,
|
|
|
|
|
.dSkip = dSkip,
|
|
|
|
|
.smat = smat
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (y = 0; y < gridSize; y++) {
|
|
|
|
|
for (x = 0; x < gridSize; x++) {
|
|
|
|
|
float *co = CCG_grid_elem_co(&dm_key, grid, x, y);
|
|
|
|
|
float *sco = CCG_grid_elem_co(&subdm_key, subgrid, x, y);
|
|
|
|
|
float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
|
|
|
|
|
float mat[3][3], disp[3];
|
|
|
|
|
|
|
|
|
|
/* construct tangent space matrix */
|
|
|
|
|
grid_tangent_matrix(mat, &dm_key, x, y, grid);
|
|
|
|
|
|
|
|
|
|
/* scale subgrid coord and calculate displacement */
|
|
|
|
|
mul_m3_v3(smat, sco);
|
|
|
|
|
sub_v3_v3v3(disp, sco, co);
|
|
|
|
|
|
|
|
|
|
/* convert difference to tangent space */
|
|
|
|
|
invert_m3(mat);
|
|
|
|
|
mul_v3_m3v3(data, mat, disp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings);
|
|
|
|
|
|
|
|
|
|
dm->release(dm);
|
|
|
|
|
subdm->release(subdm);
|
|
|
|
|
|