Sculpt dyntopo:

* Fixed multires apply base feeding bad original coordinates to
  deform modifiers.
* Roughed out some code for cache performance testing.
* Wrote skeleton code for a PBVH texel API; hasn't been tested
  yet and may be removed.
This commit is contained in:
Joseph Eagar 2021-08-20 20:36:04 -07:00
parent de1f2c41fa
commit 0d542db1e1
13 changed files with 687 additions and 8 deletions

View File

@ -642,7 +642,7 @@ void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
const CustomData_MeshMasks *cd_mask_finalize);
const struct CustomData_MeshMasks *cd_mask_finalize);
/* **** Depsgraph evaluation **** */

View File

@ -41,6 +41,12 @@ typedef struct SculptFaceRef {
intptr_t i;
} SculptFaceRef;
#if 0
typedef struct SculptLoopRef {
intptr_t i;
} SculptLoopRef;
#endif
BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
{
SculptVertRef ret = {i};
@ -745,6 +751,97 @@ void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, struc
PBVHNode *BKE_pbvh_get_node_leaf_safe(PBVH *pbvh, int i);
#if 0
typedef enum {
SCULPT_TEXTURE_UV = 1 << 0, // per-uv
// SCULPT_TEXTURE_PTEX?
} SculptTextureType;
typedef int TexLayerRef;
/*
Texture points are texels projected into 3d.
*/
typedef intptr_t TexPointRef;
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm);
typedef struct SculptTextureDef {
SculptTextureType type;
int settings_size;
void (*build_begin)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
/*vdms can cache data per node, which is freed to maintain memory limit.
they store cache in the same structure they return in buildNodeData.*/
void (*freeCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
void (*ensuredCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
/*builds all data that isn't cached.*/
void *(*buildNodeData)(PBVH *pbvh, PBVHNode *node);
bool (*validate)(PBVH *pbvh, TexLayerRef vdm);
void (*getPointsFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef **r_ids,
float ***r_cos,
float ***r_nos,
int *r_totpoint);
void (*releaseNodePoints)(
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, float **cos, float **nos);
# if 0
int (*getTrisFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef *((*r_tris)[3]),
TexPointRef **r_ids,
int tottri,
int totid);
void (*getTriInterpWeightsFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
float *((*r_tris)[3]),
SculptLoopRef ***r_src_loops,
int tottri,
int totloop);
int (*getTriCount)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
# endif
void (*getPointNeighbors)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef id,
TexPointRef **r_neighbor_ids,
int *r_totneighbor,
int maxneighbors,
TexPointRef **r_duplicates_id,
int r_totduplicate,
int maxduplicates);
void (*getPointValence)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef id);
void (*freeNodeData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, void *settings);
void (*getPointsFromIds)(
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
/*displacement texture stuff*/
// can be tangent, object space displacement, whatever
void (*worldToDelta)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
void (*deltaToWorld)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
} SculptDisplacementDef;
typedef struct SculptLayerEntry {
char name[64];
int type;
void *settings;
float factor;
struct SculptLayerEntry *parent;
} SculptLayerEntry;
#endif
#ifdef __cplusplus
}
#endif

View File

@ -235,6 +235,7 @@ set(SRC
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pbvh_displacement.c
intern/pointcache.c
intern/pointcloud.cc
intern/preferences.c
@ -792,3 +793,74 @@ if(WITH_GTESTS)
include(GTestTesting)
blender_add_test_lib(bf_blenkernel_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB}")
endif()
set(PBVH_CACHE_TEST_INC
.
../blenfont
../blenlib
../blenloader
../blentranslation
../bmesh
../depsgraph
../draw
../functions
../gpencil_modifiers
../gpu
../ikplugin
../imbuf
../makesdna
../makesrna
../modifiers
../nodes
../render
../sequencer
../shader_fx
../simulation
../../../intern/eigen
../../../intern/ghost
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/iksolver/extern
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
../../../intern/mantaflow/extern
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opensubdiv
../../../extern/curve_fit_nd
)
set(PBVH_CACHE_TEST_SRC
intern/pbvh_cache_test_main.c
)
setup_libdirs()
add_executable(pbvh_cache_test ${PBVH_CACHE_TEST_SRC} ${PBVH_CACHE_TEST_INC})
setup_platform_linker_flags(pbvh_cache_test)
target_link_libraries(pbvh_cache_test bf_blenkernel bf_bmesh bf_intern_ghost bf_blenlib bf_intern_guardedalloc)
if(WIN32)
set_target_properties(pbvh_cache_test PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
set_target_properties(pbvh_cache_test PROPERTIES
PDB_NAME "pbvh_cache_test_private"
PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
if(WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB)
# This is slightly messy, but single target generators like ninja will not have the
# CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have
# CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $<CONFIG>
# generator expression in newer cmake (2.13+) but until that time this fill have suffice.
if(CMAKE_BUILD_TYPE)
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/pbvh_cache_test_public.pdb")
else()
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/pbvh_cache_test_public.pdb")
endif()
endif()
endif()
if (WIN32)
target_link_libraries(pbvh_cache_test Vfw32.lib Imm32.lib Version.lib Comctl32.lib Shcore.lib Pathcch.lib)
endif()

View File

@ -292,6 +292,12 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
multires_reshape_apply_base_update_mesh_coords(&reshape_context);
multires_reshape_apply_base_refit_base_mesh(&reshape_context);
/**
* Tag update so deform modifiers (e.g. smooth corrective)
* get updated original coordinates
*/
DEG_id_tag_update((ID *)object, ID_RECALC_GEOMETRY);
/* Reshape to the stored final state.
* Not that the base changed, so the subdiv is to be refined to the new positions. Unfortunately,
* this can not be done foe entirely cheap: if there were deformation modifiers prior to the

View File

@ -315,6 +315,8 @@ void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_contex
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
{
ModifierData *md;
if (reshape_context->need_free_subdiv) {
BKE_subdiv_free(reshape_context->subdiv);
}

View File

@ -3395,3 +3395,190 @@ BMesh *BKE_pbvh_reorder_bmesh1(PBVH *pbvh)
return pbvh->bm;
}
// only floats! and 8 byte aligned!
typedef struct CacheParams {
float vchunk, echunk, lchunk, pchunk;
int cluster_steps, cluster_size;
} CacheParams;
typedef struct CacheParamDef {
char name[32];
float defvalue, min, max;
} CacheParamDef;
CacheParamDef pbvh_bmesh_cache_param_def[] = {{"vchunk", 512.0f, 256.0f, 1024.0f * 12.0f},
{"echunk", 512.0f, 256.0f, 1024.0f * 12.0f},
{"lchunk", 512.0f, 256.0f, 1024.0f * 12.0f},
{"pchunk", 512.0f, 256.0f, 1024.0f * 12.0f},
{"cluster_steps", 512.0f, 1.0f, 256.0f},
{"cluster_size", 512.0f, 1.0f, 8192.0f * 32.0f}};
int pbvh_bmesh_cache_test_totparams()
{
return sizeof(pbvh_bmesh_cache_param_def) / sizeof(*pbvh_bmesh_cache_param_def);
}
void pbvh_bmesh_cache_test_default_params(CacheParams *params)
{
float *fparams = (float *)params;
int totparam = pbvh_bmesh_cache_test_totparams();
for (int i = 0; i < totparam; i++) {
fparams[i] = pbvh_bmesh_cache_param_def[i].defvalue;
}
}
static void *hashco(float fx, float fy, float fz, float fdimen)
{
double x = (double)fx;
double y = (double)fy;
double z = (double)fz;
double dimen = (double)dimen;
return (void *)((intptr_t)(z * dimen * dimen + y * dimen + x));
}
void pbvh_bmesh_cache_test(CacheParams *params, BMesh **r_bm, PBVH **r_pbvh_out)
{
// build mesh
const int steps = 256;
BMAllocTemplate templ = {0, 0, 0, 0};
BMesh *bm = BM_mesh_create(&templ,
&((struct BMeshCreateParams){.use_id_elem_mask = BM_VERT | BM_FACE,
.use_id_map = true,
.use_unique_ids = true}));
// reinit pools
BLI_mempool_destroy(bm->vpool);
BLI_mempool_destroy(bm->epool);
BLI_mempool_destroy(bm->lpool);
BLI_mempool_destroy(bm->fpool);
bm->vpool = BLI_mempool_create(sizeof(BMVert), 0, (int)params->vchunk, BLI_MEMPOOL_ALLOW_ITER);
bm->epool = BLI_mempool_create(sizeof(BMEdge), 0, (int)params->vchunk, BLI_MEMPOOL_ALLOW_ITER);
bm->lpool = BLI_mempool_create(sizeof(BMLoop), 0, (int)params->vchunk, BLI_MEMPOOL_ALLOW_ITER);
bm->fpool = BLI_mempool_create(sizeof(BMFace), 0, (int)params->vchunk, BLI_MEMPOOL_ALLOW_ITER);
GHash *vhash = BLI_ghash_ptr_new("vhash");
float df = 1.0f / (float)steps;
float u, v;
int hashdimen = steps * 8;
BMVert **grid = MEM_malloc_arrayN(steps * steps, sizeof(*grid), "bmvert grid");
BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT32, "__dyntopo_vert_node");
BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT32, "__dyntopo_face_node");
BM_data_layer_add(bm, &bm->vdata, CD_SCULPT_FACE_SETS);
BM_data_layer_add(bm, &bm->vdata, CD_PAINT_MASK);
BM_data_layer_add(bm, &bm->vdata, CD_DYNTOPO_VERT);
BM_data_layer_add(bm, &bm->vdata, CD_PROP_COLOR);
for (int side = 0; side < 6; side++) {
int axis = side > 3 ? side - 3 : side;
float sign = side > 3 ? -1.0f : 1.0f;
for (int i = 0, u = 0; i < steps; i++, u += df) {
for (int j = 0, v = 0; j < steps; j++, v += df) {
float co[3];
co[axis] = u;
co[(axis + 1) % 3] = v;
co[(axis + 2) % 3] = sign;
// turn into sphere
normalize_v3(co);
void *key = hashco(co[0], co[1], co[2], hashdimen);
void **val = NULL;
if (!BLI_ghash_ensure_p(vhash, key, &val)) {
BMVert *v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP);
*val = (void *)v;
}
BMVert *v = (BMVert *)*val;
int idx = j * steps + i;
grid[idx] = v;
}
}
for (int i = 0; i < steps - 1; i++) {
for (int j = 0; j < steps - 1; j++) {
int idx1 = j * steps + i;
int idx2 = (j + 1) * steps + i;
int idx3 = (j + 1) * steps + i + 1;
int idx4 = j * steps + i + 1;
BMVert *v1 = grid[idx1];
BMVert *v2 = grid[idx2];
BMVert *v3 = grid[idx3];
BMVert *v4 = grid[idx4];
if (sign < 0) {
BMVert *vs[4] = {v4, v3, v2, v1};
BM_face_create_verts(bm, vs, 4, NULL, BM_CREATE_NOP, true);
}
else {
BMVert *vs[4] = {v1, v2, v3, v4};
BM_face_create_verts(bm, vs, 4, NULL, BM_CREATE_NOP, true);
}
}
}
}
BLI_ghash_free(vhash, NULL, NULL);
MEM_SAFE_FREE(grid);
printf("totvert: %d, totface: %d, tottri: %d\n", bm->totvert, bm->totface, bm->totface * 2);
int cd_vert_node = CustomData_get_named_layer_index(
&bm->vdata, CD_PROP_INT32, "__dyntopo_vert_node");
int cd_face_node = CustomData_get_named_layer_index(
&bm->vdata, CD_PROP_INT32, "__dyntopo_face_node");
cd_vert_node = bm->vdata.layers[cd_vert_node].offset;
cd_face_node = bm->vdata.layers[cd_face_node].offset;
const int cd_fset = CustomData_get_offset(&bm->vdata, CD_SCULPT_FACE_SETS);
const int cd_dyn_vert = CustomData_get_offset(&bm->vdata, CD_DYNTOPO_VERT);
const int cd_mask = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vcol = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
BMLog *bmlog = BM_log_create(bm, cd_dyn_vert);
PBVH *pbvh = BKE_pbvh_new();
BKE_pbvh_build_bmesh(pbvh, bm, false, bmlog, cd_vert_node, cd_face_node, cd_dyn_vert, false);
BKE_pbvh_reorder_bmesh(pbvh);
if (r_bm) {
*r_bm = bm;
}
else {
BM_mesh_free(bm);
}
if (r_pbvh_out) {
*r_pbvh_out = pbvh;
}
else {
BKE_pbvh_free(pbvh);
}
}
ATTR_NO_OPT void pbvh_bmesh_do_cache_test()
{
BMesh *bm;
PBVH *pbvh;
CacheParams params;
pbvh_bmesh_cache_test_default_params(&params);
pbvh_bmesh_cache_test(&params, &bm, &pbvh);
}

View File

@ -0,0 +1,31 @@
#include "MEM_guardedalloc.h"
#include "BLI_compiler_compat.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
#include "BKE_pbvh.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "bmesh.h"
#include "pbvh_intern.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void pbvh_bmesh_do_cache_test(void);
int main(int argc, char **argv)
{
printf("argc: %d\n", argc);
pbvh_bmesh_do_cache_test();
return 0;
}

View File

@ -0,0 +1,266 @@
#if 0
# include "MEM_guardedalloc.h"
# include "BLI_alloca.h"
# include "BLI_array.h"
# include "BLI_compiler_attrs.h"
# include "BLI_compiler_compat.h"
# include "BLI_ghash.h"
# include "BLI_linklist.h"
# include "BLI_math.h"
# include "BLI_memarena.h"
# include "BLI_memblock.h"
# include "BLI_mempool.h"
# include "BLI_utildefines.h"
# include "BLI_hash.h"
# include "BKE_context.h"
# include "BKE_global.h"
# include "BKE_image.h"
# include "BKE_mesh.h"
# include "BKE_multires.h"
# include "BKE_object.h"
# include "BKE_pbvh.h"
# include "BKE_scene.h"
# include "BLI_bitmap.h"
# include "DNA_customdata_types.h"
# include "DNA_image_types.h"
# include "DNA_material_types.h"
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_object_types.h"
# include "DNA_scene_types.h"
# include "pbvh_intern.h"
# include "bmesh.h"
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
return NULL; // implement me!
}
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm)
{
return NULL; // implement me!
}
typedef union TexelKey {
struct {
int idx; // index in image
int co_key; // used to differentiate same texel used in different 3d points in space
} key;
intptr_t i;
} TexelKey;
BLI_INLINE int calc_co_key(const float *co)
{
const int mul = 65535;
const int mask = 65535;
int x = (int)co[0] + (((int)co[0] * mul) & mask);
int y = (int)co[0] + (((int)co[0] * mul) & mask);
int z = (int)co[0] + (((int)co[0] * mul) & mask);
return BLI_hash_int_3d(x, y, z);
}
typedef struct TextureVDMSettings {
ImageUser ima_user;
ID *image;
bool tangent_space;
char uv_layer[64];
// used by texture_vdm_get_points
// BLI_bitmap *texel_used_map;
GSet *texel_used_map;
int width, height;
bool invalid;
} TextureVDMSettings;
typedef struct TextureNodeData {
TexPointRef *point_ids;
float (*point_cos)[3];
float (*point_uvs)[2];
float **point_cos_ptrs;
int totpoint;
} TextureNodeData;
void texture_vdm_begin(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
if (!settings->image) {
return;
}
Image *image = (Image *)settings->image;
int w = 0, h = 0;
BKE_image_get_size(image, &settings->ima_user, &w, &h);
// Image *image = settings->image.
settings->width = w;
settings->height = h;
// settings->texel_used_map = BLI_BITMAP_NEW(w * h, "texel_used_map");
settings->texel_used_map = BLI_gset_ptr_new("texel_used_map");
}
void texture_vdm_build_points(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
int idx;
if (!settings->uv_layer[0]) {
idx = CustomData_get_layer_index(&pbvh->bm->ldata, CD_MLOOPUV);
}
else {
idx = CustomData_get_named_layer_index(&pbvh->bm->ldata, CD_MLOOPUV, settings->uv_layer);
}
if (idx < 0) {
settings->invalid = true;
return;
}
const int cd_uv = pbvh->bm->ldata.layers[idx].offset;
const int w = settings->width, h = settings->height;
float **point_cos_ptrs = NULL;
float *uvs = NULL;
float *cos = NULL;
TexPointRef *ids = NULL;
BLI_array_declare(point_cos_ptrs);
BLI_array_declare(uvs);
BLI_array_declare(cos);
BLI_array_declare(ids);
for (int i = 0; i < node->tribuf->tottri; i++) {
PBVHTri *tri = node->tribuf->tris + i;
BMLoop *ls[3] = {(BMLoop *)tri->l[0], (BMLoop *)tri->l[1], (BMLoop *)tri->l[2]};
float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
float tricos[3][3];
copy_v3_v3(tricos[0], ls[0]->v->co);
copy_v3_v3(tricos[1], ls[1]->v->co);
copy_v3_v3(tricos[2], ls[2]->v->co);
for (int j = 0; j < 3; j++) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(ls[j], cd_uv);
minmax_v2v2_v2(min, max, luv->uv);
}
int dw = (int)((max[0] - min[0]) * (float)w + 0.000001f);
int dh = (int)((max[1] - min[1]) * (float)h + 0.000001f);
dw = MAX2(dw, 1);
dh = MAX2(dh, 1);
float du = (max[0] - min[0]) / dw;
float dv = (max[1] - min[1]) / dh;
float u = min[0], v = min[1];
for (int y = 0; y < dh; y++, v += dv) {
u = min[0];
for (int x = 0; x < dw; x++, u += du) {
int idx = y * w + x;
float co[3];
interp_barycentric_tri_v3(tricos, u, v, co);
TexelKey key;
key.key.idx = idx;
key.key.co_key = calc_co_key(co);
if (BLI_gset_haskey(settings->texel_used_map, (void *)key.i)) {
continue;
}
BLI_gset_insert(settings->texel_used_map, (void *)key.i);
BLI_array_append(uvs, u);
BLI_array_append(uvs, v);
BLI_array_append(cos, co[0]);
BLI_array_append(cos, co[1]);
BLI_array_append(cos, co[2]);
BLI_array_append(ids, (TexPointRef)key.i);
}
}
}
settings->invalid = false;
MEM_SAFE_FREE(data->point_cos);
MEM_SAFE_FREE(data->point_ids);
MEM_SAFE_FREE(data->point_uvs);
MEM_SAFE_FREE(data->point_cos_ptrs);
int totpoint = BLI_array_len(ids);
data->totpoint = totpoint;
data->point_cos_ptrs = MEM_malloc_arrayN(totpoint, sizeof(void *), "point_cos_ptrs");
// dumb casting trick
union {
float *cos;
float (*cos3)[3];
} castcos;
union {
float *uvs;
float (*uvs2)[2];
} castuvs;
castcos.cos = cos;
castuvs.uvs = uvs;
data->point_cos = castcos.cos3;
data->point_ids = ids;
data->point_uvs = castuvs.uvs2;
for (int i = 0; i < totpoint; i++) {
data->point_cos_ptrs[i] = cos + i * 3;
}
}
void texture_vdm_get_points(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef **r_ids,
float ***r_cos,
float ***r_nos,
int *r_totpoint)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
if (r_totpoint) {
*r_totpoint = data->totpoint;
}
if (r_cos) {
*r_cos = data->point_cos_ptrs;
}
if (r_ids) {
*r_ids = data->point_ids;
}
}
static SculptDisplacementDef texture_vdm = {
.type = SCULPT_TEXTURE_UV,
.settings_size = sizeof(TextureNodeData),
.getPointsFromNode = texture_vdm_get_points,
};
#endif

View File

@ -77,6 +77,8 @@ set(SRC
sculpt_transform.c
sculpt_undo.c
sculpt_uv.c
sculpt_displacement.c
sculpt_displacement.h
paint_intern.h
sculpt_intern.h

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
#pragma once

View File

@ -614,13 +614,13 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
MEM_freeN(smooth_vertex_coords);
}
static void correctivesmooth_modifier_do(ModifierData *md,
Depsgraph *depsgraph,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
uint numVerts,
struct BMEditMesh *em)
ATTR_NO_OPT static void correctivesmooth_modifier_do(ModifierData *md,
Depsgraph *depsgraph,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
uint numVerts,
struct BMEditMesh *em)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;

View File

@ -200,6 +200,16 @@ static void bpy_msgbus_subscribe_value_free_data(struct wmMsgSubscribeKey *UNUSE
/** \} */
extern void pbvh_bmesh_do_cache_test();
PyDoc_STRVAR(exec_bmesh_cache_test_doc, "internal development function\n");
static PyObject *exec_bmesh_cache_test(PyObject *self)
{
pbvh_bmesh_do_cache_test();
Py_RETURN_NONE;
}
/* -------------------------------------------------------------------- */
/** \name Public Message Bus API
* \{ */
@ -378,6 +388,10 @@ static struct PyMethodDef BPy_msgbus_methods[] = {
(PyCFunction)bpy_msgbus_clear_by_owner,
METH_O,
bpy_msgbus_clear_by_owner_doc},
{"pbvh_bmesh_do_cache_test",
(PyCFunction)exec_bmesh_cache_test,
METH_NOARGS,
exec_bmesh_cache_test_doc},
{NULL, NULL, 0, NULL},
};