Modifiers: Use implicit sharing for some bind data
Addresses #145680. In one (relatively extreme) test file with the surface deform modifier, memory usage goes from 14 GB to 4 GB, and an annoying freeze from preparing an undo step after every operation is gone. Pull Request: https://projects.blender.org/blender/blender/pulls/145705
This commit is contained in:
@@ -1577,6 +1577,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
|
||||
|
||||
static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
|
||||
{
|
||||
using namespace blender;
|
||||
MDefBindInfluence *inf;
|
||||
MDefInfluence *mdinf;
|
||||
MDefCell *cell;
|
||||
@@ -1698,7 +1699,9 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
|
||||
|
||||
/* convert MDefBindInfluences to smaller MDefInfluences */
|
||||
mmd->dyngrid = MEM_calloc_arrayN<MDefCell>(mdb->size3, "MDefDynGrid");
|
||||
mmd->dyngrid_sharing_info = implicit_sharing::info_for_mem_free(mmd->dyngrid);
|
||||
mmd->dyninfluences = MEM_calloc_arrayN<MDefInfluence>(mmd->influences_num, "MDefInfluence");
|
||||
mmd->dyninfluences_sharing_info = implicit_sharing::info_for_mem_free(mmd->dyninfluences);
|
||||
offset = 0;
|
||||
for (a = 0; a < mdb->size3; a++) {
|
||||
cell = &mmd->dyngrid[a];
|
||||
@@ -1724,6 +1727,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
|
||||
}
|
||||
|
||||
mmd->dynverts = mdb->inside;
|
||||
mmd->dynverts_sharing_info = implicit_sharing::info_for_mem_free(mmd->dynverts);
|
||||
mmd->dyngridsize = mdb->size;
|
||||
copy_v3_v3(mmd->dyncellmin, mdb->min);
|
||||
mmd->dyncellwidth = mdb->width[0];
|
||||
@@ -1749,6 +1753,7 @@ void ED_mesh_deform_bind_callback(Object *object,
|
||||
int verts_num,
|
||||
float cagemat[4][4])
|
||||
{
|
||||
using namespace blender;
|
||||
MeshDeformModifierData *mmd_orig = reinterpret_cast<MeshDeformModifierData *>(
|
||||
BKE_modifier_get_original(object, &mmd->modifier));
|
||||
MeshDeformBind mdb{};
|
||||
@@ -1784,6 +1789,7 @@ void ED_mesh_deform_bind_callback(Object *object,
|
||||
|
||||
/* assign bind variables */
|
||||
mmd_orig->bindcagecos = (float *)mdb.cagecos;
|
||||
mmd_orig->bindcagecos_sharing_info = implicit_sharing::info_for_mem_free(mmd_orig->bindcagecos);
|
||||
mmd_orig->verts_num = mdb.verts_num;
|
||||
mmd_orig->cage_verts_num = mdb.cage_verts_num;
|
||||
copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->object_to_world().ptr());
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_implicit_sharing.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
@@ -2941,7 +2942,7 @@ static wmOperatorStatus correctivesmooth_bind_exec(bContext *C, wmOperator *op)
|
||||
|
||||
const bool is_bind = (csmd->bind_coords != nullptr);
|
||||
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
implicit_sharing::free_shared_data(&csmd->bind_coords, &csmd->bind_coords_sharing_info);
|
||||
MEM_SAFE_FREE(csmd->delta_cache.deltas);
|
||||
|
||||
if (is_bind) {
|
||||
@@ -3005,6 +3006,7 @@ static bool meshdeform_poll(bContext *C)
|
||||
|
||||
static wmOperatorStatus meshdeform_bind_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace blender;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Object *ob = context_active_object(C);
|
||||
MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(
|
||||
@@ -3015,12 +3017,12 @@ static wmOperatorStatus meshdeform_bind_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
|
||||
if (mmd->bindcagecos != nullptr) {
|
||||
MEM_SAFE_FREE(mmd->bindcagecos);
|
||||
MEM_SAFE_FREE(mmd->dyngrid);
|
||||
MEM_SAFE_FREE(mmd->dyninfluences);
|
||||
MEM_SAFE_FREE(mmd->bindinfluences);
|
||||
MEM_SAFE_FREE(mmd->bindoffsets);
|
||||
MEM_SAFE_FREE(mmd->dynverts);
|
||||
implicit_sharing::free_shared_data(&mmd->bindcagecos, &mmd->bindcagecos_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dyngrid, &mmd->dyngrid_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dyninfluences, &mmd->dyninfluences_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->bindinfluences, &mmd->bindinfluences_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->bindoffsets, &mmd->bindoffsets_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dynverts, &mmd->dynverts_sharing_info);
|
||||
MEM_SAFE_FREE(mmd->bindweights); /* Deprecated */
|
||||
MEM_SAFE_FREE(mmd->bindcos); /* Deprecated */
|
||||
mmd->verts_num = 0;
|
||||
@@ -3367,10 +3369,13 @@ static wmOperatorStatus laplaciandeform_bind_exec(bContext *C, wmOperator *op)
|
||||
* happening for binding or not. So we copy all the required data here. */
|
||||
lmd->verts_num = lmd_eval->verts_num;
|
||||
if (lmd_eval->vertexco == nullptr) {
|
||||
MEM_SAFE_FREE(lmd->vertexco);
|
||||
implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
|
||||
}
|
||||
else {
|
||||
lmd->vertexco = static_cast<float *>(MEM_dupallocN(lmd_eval->vertexco));
|
||||
implicit_sharing::copy_shared_pointer(lmd_eval->vertexco,
|
||||
lmd_eval->vertexco_sharing_info,
|
||||
&lmd->vertexco,
|
||||
&lmd->vertexco_sharing_info);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_implicit_sharing.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_defs.h"
|
||||
@@ -1069,20 +1070,26 @@ typedef struct MeshDeformModifierData {
|
||||
/* result of static binding */
|
||||
/** Influences. */
|
||||
MDefInfluence *bindinfluences;
|
||||
const ImplicitSharingInfoHandle *bindinfluences_sharing_info;
|
||||
/** Offsets into influences array. */
|
||||
int *bindoffsets;
|
||||
const ImplicitSharingInfoHandle *bindoffsets_sharing_info;
|
||||
/** Coordinates that cage was bound with. */
|
||||
float *bindcagecos;
|
||||
const ImplicitSharingInfoHandle *bindcagecos_sharing_info;
|
||||
/** Total vertices in mesh and cage. */
|
||||
int verts_num, cage_verts_num;
|
||||
|
||||
/* result of dynamic binding */
|
||||
/** Grid with dynamic binding cell points. */
|
||||
MDefCell *dyngrid;
|
||||
const ImplicitSharingInfoHandle *dyngrid_sharing_info;
|
||||
/** Dynamic binding vertex influences. */
|
||||
MDefInfluence *dyninfluences;
|
||||
const ImplicitSharingInfoHandle *dyninfluences_sharing_info;
|
||||
/** Is this vertex bound or not? */
|
||||
int *dynverts;
|
||||
const ImplicitSharingInfoHandle *dynverts_sharing_info;
|
||||
/** Size of the dynamic bind grid. */
|
||||
int dyngridsize;
|
||||
/** Total number of vertex influences. */
|
||||
@@ -1969,6 +1976,7 @@ typedef struct CorrectiveSmoothModifierData {
|
||||
/* positions set during 'bind' operator
|
||||
* use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
|
||||
float (*bind_coords)[3];
|
||||
const ImplicitSharingInfoHandle *bind_coords_sharing_info;
|
||||
|
||||
/* NOTE: -1 is used to bind. */
|
||||
unsigned int bind_coords_num;
|
||||
@@ -2123,6 +2131,7 @@ typedef struct LaplacianDeformModifierData {
|
||||
char anchor_grp_name[/*MAX_VGROUP_NAME*/ 64];
|
||||
int verts_num, repeat;
|
||||
float *vertexco;
|
||||
const ImplicitSharingInfoHandle *vertexco_sharing_info;
|
||||
/** Runtime only. */
|
||||
void *cache_system;
|
||||
/** #LaplacianDeformModifierFlag. */
|
||||
@@ -2335,7 +2344,7 @@ typedef struct SurfaceDeformModifierData {
|
||||
struct Object *target;
|
||||
/** Vertex bind data. */
|
||||
SDefVert *verts;
|
||||
void *_pad1;
|
||||
const ImplicitSharingInfoHandle *verts_sharing_info;
|
||||
float falloff;
|
||||
/* Number of vertices on the deformed mesh upon the bind process. */
|
||||
unsigned int mesh_verts_num;
|
||||
|
||||
@@ -1814,7 +1814,7 @@ static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain,
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
|
||||
|
||||
if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
blender::implicit_sharing::free_shared_data(&csmd, &csmd->bind_coords_sharing_info);
|
||||
csmd->bind_coords_num = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,9 +67,10 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
if (csmd->bind_coords) {
|
||||
tcsmd->bind_coords = static_cast<float(*)[3]>(MEM_dupallocN(csmd->bind_coords));
|
||||
}
|
||||
blender::implicit_sharing::copy_shared_pointer(csmd->bind_coords,
|
||||
csmd->bind_coords_sharing_info,
|
||||
&tcsmd->bind_coords,
|
||||
&tcsmd->bind_coords_sharing_info);
|
||||
|
||||
tcsmd->delta_cache.deltas = nullptr;
|
||||
tcsmd->delta_cache.deltas_num = 0;
|
||||
@@ -77,7 +78,7 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
|
||||
|
||||
static void freeBind(CorrectiveSmoothModifierData *csmd)
|
||||
{
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
blender::implicit_sharing::free_shared_data(&csmd->bind_coords, &csmd->bind_coords_sharing_info);
|
||||
MEM_SAFE_FREE(csmd->delta_cache.deltas);
|
||||
|
||||
csmd->bind_coords_num = 0;
|
||||
@@ -551,6 +552,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
|
||||
blender::MutableSpan<blender::float3> vertexCos,
|
||||
BMEditMesh *em)
|
||||
{
|
||||
using namespace blender;
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
|
||||
const bool force_delta_cache_update =
|
||||
@@ -575,13 +577,19 @@ static void correctivesmooth_modifier_do(ModifierData *md,
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
BLI_assert(csmd->bind_coords == nullptr);
|
||||
csmd->bind_coords = MEM_malloc_arrayN<float[3]>(size_t(vertexCos.size()), __func__);
|
||||
csmd->bind_coords_sharing_info = implicit_sharing::info_for_mem_free(csmd->bind_coords);
|
||||
memcpy(csmd->bind_coords, vertexCos.data(), size_t(vertexCos.size_in_bytes()));
|
||||
csmd->bind_coords_num = uint(vertexCos.size());
|
||||
BLI_assert(csmd->bind_coords != nullptr);
|
||||
|
||||
/* Copy bound data to the original modifier. */
|
||||
CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *)
|
||||
BKE_modifier_get_original(ob, &csmd->modifier);
|
||||
csmd_orig->bind_coords = static_cast<float(*)[3]>(MEM_dupallocN(csmd->bind_coords));
|
||||
implicit_sharing::copy_shared_pointer(csmd->bind_coords,
|
||||
csmd->bind_coords_sharing_info,
|
||||
&csmd_orig->bind_coords,
|
||||
&csmd_orig->bind_coords_sharing_info);
|
||||
|
||||
csmd_orig->bind_coords_num = csmd->bind_coords_num;
|
||||
}
|
||||
else {
|
||||
@@ -780,13 +788,21 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
|
||||
* binding data, can save a significant amount of memory. */
|
||||
csmd.bind_coords_num = 0;
|
||||
csmd.bind_coords = nullptr;
|
||||
csmd.bind_coords_sharing_info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BLO_write_struct_at_address(writer, CorrectiveSmoothModifierData, md, &csmd);
|
||||
|
||||
if (csmd.bind_coords != nullptr) {
|
||||
BLO_write_float3_array(writer, csmd.bind_coords_num, (float *)csmd.bind_coords);
|
||||
BLO_write_shared(writer,
|
||||
csmd.bind_coords,
|
||||
sizeof(float[3]) * csmd.bind_coords_num,
|
||||
csmd.bind_coords_sharing_info,
|
||||
[&]() {
|
||||
BLO_write_float3_array(
|
||||
writer, csmd.bind_coords_num, (const float *)csmd.bind_coords);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,7 +811,10 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
|
||||
if (csmd->bind_coords) {
|
||||
BLO_read_float3_array(reader, int(csmd->bind_coords_num), (float **)&csmd->bind_coords);
|
||||
csmd->bind_coords_sharing_info = BLO_read_shared(reader, &csmd->bind_coords, [&]() {
|
||||
BLO_read_float3_array(reader, int(csmd->bind_coords_num), (float **)&csmd->bind_coords);
|
||||
return blender::implicit_sharing::info_for_mem_free(csmd->bind_coords);
|
||||
});
|
||||
}
|
||||
|
||||
/* runtime only */
|
||||
|
||||
@@ -576,6 +576,7 @@ static void initSystem(
|
||||
memcpy(sys->co, vertexCos, sizeof(float[3]) * verts_num);
|
||||
MEM_freeN(index_anchors);
|
||||
lmd->vertexco = MEM_malloc_arrayN<float>(3 * size_t(verts_num), __func__);
|
||||
lmd->vertexco_sharing_info = blender::implicit_sharing::info_for_mem_free(lmd->vertexco);
|
||||
memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * verts_num);
|
||||
lmd->verts_num = verts_num;
|
||||
|
||||
@@ -702,7 +703,7 @@ static void LaplacianDeformModifier_do(
|
||||
else if (lmd->verts_num > 0 && lmd->verts_num == verts_num) {
|
||||
filevertexCos = MEM_malloc_arrayN<float[3]>(size_t(verts_num), "TempDeformCoordinates");
|
||||
memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
|
||||
MEM_SAFE_FREE(lmd->vertexco);
|
||||
blender::implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
|
||||
lmd->verts_num = 0;
|
||||
initSystem(lmd, ob, mesh, filevertexCos, verts_num);
|
||||
sys = static_cast<LaplacianSystem *>(lmd->cache_system);
|
||||
@@ -736,7 +737,8 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
tlmd->vertexco = static_cast<float *>(MEM_dupallocN(lmd->vertexco));
|
||||
blender::implicit_sharing::copy_shared_pointer(
|
||||
lmd->vertexco, lmd->vertexco_sharing_info, &tlmd->vertexco, &tlmd->vertexco_sharing_info);
|
||||
tlmd->cache_system = nullptr;
|
||||
}
|
||||
|
||||
@@ -777,7 +779,7 @@ static void free_data(ModifierData *md)
|
||||
if (sys) {
|
||||
deleteLaplacianSystem(sys);
|
||||
}
|
||||
MEM_SAFE_FREE(lmd->vertexco);
|
||||
blender::implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
|
||||
lmd->verts_num = 0;
|
||||
}
|
||||
|
||||
@@ -826,13 +828,17 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
|
||||
* binding data, can save a significant amount of memory. */
|
||||
lmd.verts_num = 0;
|
||||
lmd.vertexco = nullptr;
|
||||
lmd.vertexco_sharing_info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BLO_write_struct_at_address(writer, LaplacianDeformModifierData, md, &lmd);
|
||||
|
||||
if (lmd.vertexco != nullptr) {
|
||||
BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
|
||||
BLO_write_shared(
|
||||
writer, lmd.vertexco, sizeof(float[3]) * lmd.verts_num, lmd.vertexco_sharing_info, [&]() {
|
||||
BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,7 +846,12 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
|
||||
|
||||
BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
|
||||
if (lmd->vertexco) {
|
||||
lmd->vertexco_sharing_info = BLO_read_shared(reader, &lmd->vertexco, [&]() {
|
||||
BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
|
||||
return blender::implicit_sharing::info_for_mem_free(lmd->vertexco);
|
||||
});
|
||||
}
|
||||
lmd->cache_system = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,26 +52,15 @@ static void init_data(ModifierData *md)
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
using namespace blender;
|
||||
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
|
||||
|
||||
if (mmd->bindinfluences) {
|
||||
MEM_freeN(mmd->bindinfluences);
|
||||
}
|
||||
if (mmd->bindoffsets) {
|
||||
MEM_freeN(mmd->bindoffsets);
|
||||
}
|
||||
if (mmd->bindcagecos) {
|
||||
MEM_freeN(mmd->bindcagecos);
|
||||
}
|
||||
if (mmd->dyngrid) {
|
||||
MEM_freeN(mmd->dyngrid);
|
||||
}
|
||||
if (mmd->dyninfluences) {
|
||||
MEM_freeN(mmd->dyninfluences);
|
||||
}
|
||||
if (mmd->dynverts) {
|
||||
MEM_freeN(mmd->dynverts);
|
||||
}
|
||||
implicit_sharing::free_shared_data(&mmd->bindinfluences, &mmd->bindinfluences_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->bindoffsets, &mmd->bindoffsets_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->bindcagecos, &mmd->bindcagecos_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dyngrid, &mmd->dyngrid_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dyninfluences, &mmd->dyninfluences_sharing_info);
|
||||
implicit_sharing::free_shared_data(&mmd->dynverts, &mmd->dynverts_sharing_info);
|
||||
if (mmd->bindweights) {
|
||||
MEM_freeN(mmd->bindweights); /* deprecated */
|
||||
}
|
||||
@@ -82,29 +71,32 @@ static void free_data(ModifierData *md)
|
||||
|
||||
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
|
||||
{
|
||||
using namespace blender;
|
||||
const MeshDeformModifierData *mmd = (const MeshDeformModifierData *)md;
|
||||
MeshDeformModifierData *tmmd = (MeshDeformModifierData *)target;
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
if (mmd->bindinfluences) {
|
||||
tmmd->bindinfluences = static_cast<MDefInfluence *>(MEM_dupallocN(mmd->bindinfluences));
|
||||
}
|
||||
if (mmd->bindoffsets) {
|
||||
tmmd->bindoffsets = static_cast<int *>(MEM_dupallocN(mmd->bindoffsets));
|
||||
}
|
||||
if (mmd->bindcagecos) {
|
||||
tmmd->bindcagecos = static_cast<float *>(MEM_dupallocN(mmd->bindcagecos));
|
||||
}
|
||||
if (mmd->dyngrid) {
|
||||
tmmd->dyngrid = static_cast<MDefCell *>(MEM_dupallocN(mmd->dyngrid));
|
||||
}
|
||||
if (mmd->dyninfluences) {
|
||||
tmmd->dyninfluences = static_cast<MDefInfluence *>(MEM_dupallocN(mmd->dyninfluences));
|
||||
}
|
||||
if (mmd->dynverts) {
|
||||
tmmd->dynverts = static_cast<int *>(MEM_dupallocN(mmd->dynverts));
|
||||
}
|
||||
implicit_sharing::copy_shared_pointer(mmd->bindinfluences,
|
||||
mmd->bindinfluences_sharing_info,
|
||||
&tmmd->bindinfluences,
|
||||
&tmmd->bindinfluences_sharing_info);
|
||||
implicit_sharing::copy_shared_pointer(mmd->bindoffsets,
|
||||
mmd->bindoffsets_sharing_info,
|
||||
&tmmd->bindoffsets,
|
||||
&tmmd->bindoffsets_sharing_info);
|
||||
implicit_sharing::copy_shared_pointer(mmd->bindcagecos,
|
||||
mmd->bindcagecos_sharing_info,
|
||||
&tmmd->bindcagecos,
|
||||
&tmmd->bindcagecos_sharing_info);
|
||||
implicit_sharing::copy_shared_pointer(
|
||||
mmd->dyngrid, mmd->dyngrid_sharing_info, &tmmd->dyngrid, &tmmd->dyngrid_sharing_info);
|
||||
implicit_sharing::copy_shared_pointer(mmd->dyninfluences,
|
||||
mmd->dyninfluences_sharing_info,
|
||||
&tmmd->dyninfluences,
|
||||
&tmmd->dyninfluences_sharing_info);
|
||||
implicit_sharing::copy_shared_pointer(
|
||||
mmd->dynverts, mmd->dynverts_sharing_info, &tmmd->dynverts, &tmmd->dynverts_sharing_info);
|
||||
if (mmd->bindweights) {
|
||||
tmmd->bindweights = static_cast<float *>(MEM_dupallocN(mmd->bindweights)); /* deprecated */
|
||||
}
|
||||
@@ -322,7 +314,7 @@ static void meshdeformModifier_do(ModifierData *md,
|
||||
Mesh *cagemesh;
|
||||
const MDeformVert *dvert = nullptr;
|
||||
float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
|
||||
float(*bindcagecos)[3];
|
||||
const float(*bindcagecos)[3];
|
||||
int a, cage_verts_num, defgrp_index;
|
||||
MeshdeformUserdata data;
|
||||
|
||||
@@ -397,7 +389,7 @@ static void meshdeformModifier_do(ModifierData *md,
|
||||
|
||||
/* setup deformation data */
|
||||
BKE_mesh_wrapper_vert_coords_copy(cagemesh, dco.as_mutable_span().take_front(cage_verts_num));
|
||||
bindcagecos = (float(*)[3])mmd->bindcagecos;
|
||||
bindcagecos = (const float(*)[3])mmd->bindcagecos;
|
||||
|
||||
for (a = 0; a < cage_verts_num; a++) {
|
||||
/* Get cage vertex in world-space with binding transform. */
|
||||
@@ -440,6 +432,7 @@ static void deform_verts(ModifierData *md,
|
||||
|
||||
void BKE_modifier_mdef_compact_influences(ModifierData *md)
|
||||
{
|
||||
using namespace blender;
|
||||
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
|
||||
float weight, totweight;
|
||||
int influences_num, verts_num, cage_verts_num, a, b;
|
||||
@@ -465,7 +458,9 @@ void BKE_modifier_mdef_compact_influences(ModifierData *md)
|
||||
|
||||
/* allocate bind influences */
|
||||
mmd->bindinfluences = MEM_calloc_arrayN<MDefInfluence>(mmd->influences_num, __func__);
|
||||
mmd->bindinfluences_sharing_info = implicit_sharing::info_for_mem_free(mmd->bindinfluences);
|
||||
mmd->bindoffsets = MEM_calloc_arrayN<int>(size_t(verts_num) + 1, __func__);
|
||||
mmd->bindoffsets_sharing_info = implicit_sharing::info_for_mem_free(mmd->bindoffsets);
|
||||
|
||||
/* write influences */
|
||||
influences_num = 0;
|
||||
@@ -548,15 +543,21 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
|
||||
* binding data, can save a significant amount of memory. */
|
||||
mmd.influences_num = 0;
|
||||
mmd.bindinfluences = nullptr;
|
||||
mmd.bindinfluences_sharing_info = nullptr;
|
||||
mmd.verts_num = 0;
|
||||
mmd.bindoffsets = nullptr;
|
||||
mmd.bindoffsets_sharing_info = nullptr;
|
||||
mmd.cage_verts_num = 0;
|
||||
mmd.bindcagecos = nullptr;
|
||||
mmd.bindcagecos_sharing_info = nullptr;
|
||||
mmd.dyngridsize = 0;
|
||||
mmd.dyngrid = nullptr;
|
||||
mmd.dyngrid_sharing_info = nullptr;
|
||||
mmd.influences_num = 0;
|
||||
mmd.dyninfluences = nullptr;
|
||||
mmd.dyninfluences_sharing_info = nullptr;
|
||||
mmd.dynverts = nullptr;
|
||||
mmd.dynverts_sharing_info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,21 +565,50 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
|
||||
|
||||
BLO_write_struct_at_address(writer, MeshDeformModifierData, md, &mmd);
|
||||
|
||||
BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.bindinfluences);
|
||||
BLO_write_shared(writer,
|
||||
mmd.bindinfluences,
|
||||
sizeof(MDefInfluence) * mmd.influences_num,
|
||||
mmd.bindinfluences_sharing_info,
|
||||
[&]() {
|
||||
BLO_write_struct_array(
|
||||
writer, MDefInfluence, mmd.influences_num, mmd.bindinfluences);
|
||||
});
|
||||
|
||||
/* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
|
||||
* case `verts_num == 0`, since `bindoffset` is then nullptr, not a size 1 allocated array. */
|
||||
if (mmd.verts_num > 0) {
|
||||
BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets);
|
||||
BLO_write_shared(writer,
|
||||
mmd.bindoffsets,
|
||||
sizeof(int) * (mmd.verts_num + 1),
|
||||
mmd.bindoffsets_sharing_info,
|
||||
[&]() { BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets); });
|
||||
}
|
||||
else {
|
||||
BLI_assert(mmd.bindoffsets == nullptr);
|
||||
}
|
||||
|
||||
BLO_write_float3_array(writer, mmd.cage_verts_num, mmd.bindcagecos);
|
||||
BLO_write_struct_array(writer, MDefCell, size * size * size, mmd.dyngrid);
|
||||
BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.dyninfluences);
|
||||
BLO_write_int32_array(writer, mmd.verts_num, mmd.dynverts);
|
||||
BLO_write_shared(writer,
|
||||
mmd.bindcagecos,
|
||||
sizeof(float[3]) * mmd.cage_verts_num,
|
||||
mmd.bindcagecos_sharing_info,
|
||||
[&]() { BLO_write_float3_array(writer, mmd.cage_verts_num, mmd.bindcagecos); });
|
||||
BLO_write_shared(
|
||||
writer, mmd.dyngrid, sizeof(MDefCell) * size * size * size, mmd.dyngrid_sharing_info, [&]() {
|
||||
BLO_write_struct_array(writer, MDefCell, size * size * size, mmd.dyngrid);
|
||||
});
|
||||
BLO_write_shared(writer,
|
||||
mmd.dyninfluences,
|
||||
sizeof(MDefInfluence) * mmd.influences_num,
|
||||
mmd.dyninfluences_sharing_info,
|
||||
[&]() {
|
||||
BLO_write_struct_array(
|
||||
writer, MDefInfluence, mmd.influences_num, mmd.dyninfluences);
|
||||
});
|
||||
BLO_write_shared(writer,
|
||||
mmd.dynverts,
|
||||
sizeof(MDefInfluence) * mmd.verts_num,
|
||||
mmd.dynverts_sharing_info,
|
||||
[&]() { BLO_write_int32_array(writer, mmd.verts_num, mmd.dynverts); });
|
||||
}
|
||||
|
||||
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
@@ -586,18 +616,48 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
|
||||
const int size = mmd->dyngridsize;
|
||||
|
||||
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->bindinfluences);
|
||||
if (mmd->bindinfluences) {
|
||||
mmd->bindinfluences_sharing_info = BLO_read_shared(reader, &mmd->bindinfluences, [&]() {
|
||||
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->bindinfluences);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->bindinfluences);
|
||||
});
|
||||
}
|
||||
|
||||
/* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
|
||||
* case `verts_num == 0`, since `bindoffset` is then nullptr, not a size 1 allocated array. */
|
||||
if (mmd->verts_num > 0) {
|
||||
BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
|
||||
if (mmd->bindoffsets) {
|
||||
mmd->bindoffsets_sharing_info = BLO_read_shared(reader, &mmd->bindoffsets, [&]() {
|
||||
BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->bindoffsets);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
|
||||
BLO_read_struct_array(reader, MDefCell, size * size * size, &mmd->dyngrid);
|
||||
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->dyninfluences);
|
||||
BLO_read_int32_array(reader, mmd->verts_num, &mmd->dynverts);
|
||||
if (mmd->bindcagecos) {
|
||||
mmd->bindcagecos_sharing_info = BLO_read_shared(reader, &mmd->bindcagecos, [&]() {
|
||||
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->bindcagecos);
|
||||
});
|
||||
}
|
||||
if (mmd->dyngrid) {
|
||||
mmd->dyngrid_sharing_info = BLO_read_shared(reader, &mmd->dyngrid, [&]() {
|
||||
BLO_read_struct_array(reader, MDefCell, size * size * size, &mmd->dyngrid);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->dyngrid);
|
||||
});
|
||||
}
|
||||
if (mmd->dyninfluences) {
|
||||
mmd->dyninfluences_sharing_info = BLO_read_shared(reader, &mmd->dyninfluences, [&]() {
|
||||
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->dyninfluences);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->dyninfluences);
|
||||
});
|
||||
}
|
||||
if (mmd->dynverts) {
|
||||
mmd->dynverts_sharing_info = BLO_read_shared(reader, &mmd->dynverts, [&]() {
|
||||
BLO_read_int32_array(reader, mmd->verts_num, &mmd->dynverts);
|
||||
return blender::implicit_sharing::info_for_mem_free(mmd->dynverts);
|
||||
});
|
||||
}
|
||||
|
||||
/* Deprecated storage. */
|
||||
BLO_read_float_array(reader, mmd->verts_num, &mmd->bindweights);
|
||||
|
||||
@@ -208,23 +208,37 @@ static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_
|
||||
}
|
||||
}
|
||||
|
||||
class BindVertsImplicitSharing : public blender::ImplicitSharingInfo {
|
||||
public:
|
||||
SDefVert *verts;
|
||||
int bind_verts_num;
|
||||
|
||||
BindVertsImplicitSharing(SDefVert *data, int bind_verts_num)
|
||||
: verts(data), bind_verts_num(bind_verts_num)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
{
|
||||
for (int i = 0; i < this->bind_verts_num; i++) {
|
||||
if (this->verts[i].binds) {
|
||||
for (int j = 0; j < this->verts[i].binds_num; j++) {
|
||||
MEM_SAFE_FREE(this->verts[i].binds[j].vert_inds);
|
||||
MEM_SAFE_FREE(this->verts[i].binds[j].vert_weights);
|
||||
}
|
||||
MEM_freeN(this->verts[i].binds);
|
||||
}
|
||||
}
|
||||
MEM_freeN(verts);
|
||||
MEM_delete(this);
|
||||
}
|
||||
};
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
|
||||
|
||||
if (smd->verts) {
|
||||
for (int i = 0; i < smd->bind_verts_num; i++) {
|
||||
if (smd->verts[i].binds) {
|
||||
for (int j = 0; j < smd->verts[i].binds_num; j++) {
|
||||
MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds);
|
||||
MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights);
|
||||
}
|
||||
MEM_freeN(smd->verts[i].binds);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(smd->verts);
|
||||
}
|
||||
blender::implicit_sharing::free_shared_data(&smd->verts, &smd->verts_sharing_info);
|
||||
}
|
||||
|
||||
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
|
||||
@@ -234,27 +248,8 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
if (smd->verts) {
|
||||
tsmd->verts = static_cast<SDefVert *>(MEM_dupallocN(smd->verts));
|
||||
|
||||
for (int i = 0; i < smd->bind_verts_num; i++) {
|
||||
if (smd->verts[i].binds) {
|
||||
tsmd->verts[i].binds = static_cast<SDefBind *>(MEM_dupallocN(smd->verts[i].binds));
|
||||
|
||||
for (int j = 0; j < smd->verts[i].binds_num; j++) {
|
||||
if (smd->verts[i].binds[j].vert_inds) {
|
||||
tsmd->verts[i].binds[j].vert_inds = static_cast<uint *>(
|
||||
MEM_dupallocN(smd->verts[i].binds[j].vert_inds));
|
||||
}
|
||||
|
||||
if (smd->verts[i].binds[j].vert_weights) {
|
||||
tsmd->verts[i].binds[j].vert_weights = static_cast<float *>(
|
||||
MEM_dupallocN(smd->verts[i].binds[j].vert_weights));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
blender::implicit_sharing::copy_shared_pointer(
|
||||
smd->verts, smd->verts_sharing_info, &tsmd->verts, &tsmd->verts_sharing_info);
|
||||
}
|
||||
|
||||
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||
@@ -1147,12 +1142,26 @@ static void compactSparseBinds(SurfaceDeformModifierData *smd)
|
||||
|
||||
for (uint i = 0; i < smd->mesh_verts_num; i++) {
|
||||
if (smd->verts[i].binds_num > 0) {
|
||||
smd->verts[smd->bind_verts_num++] = smd->verts[i];
|
||||
smd->bind_verts_num++;
|
||||
}
|
||||
}
|
||||
|
||||
smd->verts = static_cast<SDefVert *>(MEM_reallocN_id(
|
||||
smd->verts, sizeof(*smd->verts) * smd->bind_verts_num, "SDefBindVerts (sparse)"));
|
||||
SDefVert *new_verts = MEM_malloc_arrayN<SDefVert>(size_t(smd->bind_verts_num), __func__);
|
||||
|
||||
/* Move data to new_verts. */
|
||||
BLI_assert(smd->verts_sharing_info->is_mutable());
|
||||
int dst_index = 0;
|
||||
for (uint i = 0; i < smd->mesh_verts_num; i++) {
|
||||
if (smd->verts[i].binds_num > 0) {
|
||||
new_verts[dst_index++] = smd->verts[i];
|
||||
smd->verts[i] = {};
|
||||
}
|
||||
}
|
||||
|
||||
smd->verts_sharing_info->remove_user_and_delete_if_last();
|
||||
smd->verts = new_verts;
|
||||
smd->verts_sharing_info = MEM_new<BindVertsImplicitSharing>(
|
||||
__func__, smd->verts, smd->bind_verts_num);
|
||||
}
|
||||
|
||||
static bool surfacedeformBind(Object *ob,
|
||||
@@ -1165,6 +1174,7 @@ static bool surfacedeformBind(Object *ob,
|
||||
Mesh *target,
|
||||
Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
const blender::Span<blender::float3> positions = target->vert_positions();
|
||||
const blender::Span<blender::int2> edges = target->edges();
|
||||
const blender::OffsetIndices polys = target->faces();
|
||||
@@ -1202,13 +1212,14 @@ static bool surfacedeformBind(Object *ob,
|
||||
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
|
||||
return false;
|
||||
}
|
||||
smd_orig->verts_sharing_info = MEM_new<BindVertsImplicitSharing>(
|
||||
__func__, smd_orig->verts, verts_num);
|
||||
|
||||
blender::bke::BVHTreeFromMesh treeData = target->bvh_corner_tris();
|
||||
if (treeData.tree == nullptr) {
|
||||
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
|
||||
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
|
||||
MEM_freeN(smd_orig->verts);
|
||||
smd_orig->verts = nullptr;
|
||||
implicit_sharing::free_shared_data(&smd_orig->verts, &smd_orig->verts_sharing_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1218,8 +1229,7 @@ static bool surfacedeformBind(Object *ob,
|
||||
BKE_modifier_set_error(
|
||||
ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
|
||||
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
|
||||
MEM_freeN(smd_orig->verts);
|
||||
smd_orig->verts = nullptr;
|
||||
implicit_sharing::free_shared_data(&smd_orig->verts, &smd_orig->verts_sharing_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1633,34 +1643,41 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
|
||||
* binding data, can save a significant amount of memory. */
|
||||
smd.bind_verts_num = 0;
|
||||
smd.verts = nullptr;
|
||||
smd.verts_sharing_info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BLO_write_struct_at_address(writer, SurfaceDeformModifierData, md, &smd);
|
||||
|
||||
if (smd.verts != nullptr) {
|
||||
SDefVert *bind_verts = smd.verts;
|
||||
BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
|
||||
BLO_write_shared(
|
||||
writer, smd.verts, sizeof(SDefVert) * smd.bind_verts_num, smd.verts_sharing_info, [&]() {
|
||||
SDefVert *bind_verts = smd.verts;
|
||||
BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
|
||||
|
||||
for (int i = 0; i < smd.bind_verts_num; i++) {
|
||||
BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
|
||||
for (int i = 0; i < smd.bind_verts_num; i++) {
|
||||
BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
|
||||
|
||||
if (bind_verts[i].binds) {
|
||||
for (int j = 0; j < bind_verts[i].binds_num; j++) {
|
||||
BLO_write_uint32_array(
|
||||
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
|
||||
if (bind_verts[i].binds) {
|
||||
for (int j = 0; j < bind_verts[i].binds_num; j++) {
|
||||
BLO_write_uint32_array(
|
||||
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
|
||||
|
||||
if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
|
||||
{
|
||||
BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
|
||||
if (ELEM(bind_verts[i].binds[j].mode,
|
||||
MOD_SDEF_MODE_CENTROID,
|
||||
MOD_SDEF_MODE_CORNER_TRIS))
|
||||
{
|
||||
BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
|
||||
}
|
||||
else {
|
||||
BLO_write_float_array(writer,
|
||||
bind_verts[i].binds[j].verts_num,
|
||||
bind_verts[i].binds[j].vert_weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLO_write_float_array(
|
||||
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1668,28 +1685,33 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
|
||||
|
||||
BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
|
||||
|
||||
if (smd->verts) {
|
||||
for (int i = 0; i < smd->bind_verts_num; i++) {
|
||||
BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
|
||||
smd->verts_sharing_info = BLO_read_shared(reader, &smd->verts, [&]() {
|
||||
BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
|
||||
for (int i = 0; i < smd->bind_verts_num; i++) {
|
||||
BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
|
||||
|
||||
if (smd->verts[i].binds) {
|
||||
for (int j = 0; j < smd->verts[i].binds_num; j++) {
|
||||
BLO_read_uint32_array(
|
||||
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
|
||||
if (smd->verts[i].binds) {
|
||||
for (int j = 0; j < smd->verts[i].binds_num; j++) {
|
||||
BLO_read_uint32_array(
|
||||
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
|
||||
|
||||
if (ELEM(smd->verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
|
||||
{
|
||||
BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
|
||||
}
|
||||
else {
|
||||
BLO_read_float_array(
|
||||
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
|
||||
if (ELEM(smd->verts[i].binds[j].mode,
|
||||
MOD_SDEF_MODE_CENTROID,
|
||||
MOD_SDEF_MODE_CORNER_TRIS))
|
||||
{
|
||||
BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
|
||||
}
|
||||
else {
|
||||
BLO_read_float_array(
|
||||
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MEM_new<BindVertsImplicitSharing>(
|
||||
"BindVertsImplicitSharing", smd->verts, smd->bind_verts_num);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user