Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc (renamed from source/blender/blenkernel/intern/DerivedMesh.c)454
-rw-r--r--source/blender/blenkernel/intern/anim_data.c1
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c79
-rw-r--r--source/blender/blenkernel/intern/appdir.c93
-rw-r--r--source/blender/blenkernel/intern/armature.c2
-rw-r--r--source/blender/blenkernel/intern/asset.c151
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc52
-rw-r--r--source/blender/blenkernel/intern/blender.c1
-rw-r--r--source/blender/blenkernel/intern/blendfile.c3
-rw-r--r--source/blender/blenkernel/intern/boids.c1
-rw-r--r--source/blender/blenkernel/intern/brush.c10
-rw-r--r--source/blender/blenkernel/intern/collection.c25
-rw-r--r--source/blender/blenkernel/intern/constraint.c2
-rw-r--r--source/blender/blenkernel/intern/context.c12
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.c87
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc190
-rw-r--r--source/blender/blenkernel/intern/customdata.c16
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c1
-rw-r--r--source/blender/blenkernel/intern/font.c8
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc46
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c3
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c195
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c2
-rw-r--r--source/blender/blenkernel/intern/icons.cc (renamed from source/blender/blenkernel/intern/icons.c)370
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c2
-rw-r--r--source/blender/blenkernel/intern/idtype.c1
-rw-r--r--source/blender/blenkernel/intern/image.c18
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c2
-rw-r--r--source/blender/blenkernel/intern/ipo.c25
-rw-r--r--source/blender/blenkernel/intern/key.c15
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c12
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c5
-rw-r--r--source/blender/blenkernel/intern/lib_override.c38
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c3
-rw-r--r--source/blender/blenkernel/intern/mesh.c51
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc505
-rw-r--r--source/blender/blenkernel/intern/modifier.c3
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.h2
-rw-r--r--source/blender/blenkernel/intern/nla.c7
-rw-r--r--source/blender/blenkernel/intern/node.c73
-rw-r--r--source/blender/blenkernel/intern/object.c28
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c53
-rw-r--r--source/blender/blenkernel/intern/object_update.c1
-rw-r--r--source/blender/blenkernel/intern/particle.c1
-rw-r--r--source/blender/blenkernel/intern/particle_child.c1
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c1
-rw-r--r--source/blender/blenkernel/intern/particle_system.c29
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc36
-rw-r--r--source/blender/blenkernel/intern/preferences.c119
-rw-r--r--source/blender/blenkernel/intern/scene.c14
-rw-r--r--source/blender/blenkernel/intern/screen.c12
-rw-r--r--source/blender/blenkernel/intern/softbody.c1
-rw-r--r--source/blender/blenkernel/intern/sound.c8
-rw-r--r--source/blender/blenkernel/intern/text.c13
-rw-r--r--source/blender/blenkernel/intern/volume.cc8
57 files changed, 2350 insertions, 545 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.cc
index eeff04788f9..b8219dcf7ac 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -21,8 +21,8 @@
* \ingroup bke
*/
-#include <limits.h>
-#include <string.h>
+#include <climits>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -38,16 +38,19 @@
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
+#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_DerivedMesh.h"
#include "BKE_bvhutils.h"
#include "BKE_colorband.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_geometry_set.hh"
#include "BKE_key.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -81,7 +84,7 @@
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_MESH(mesh) \
- (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+ (BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_MESH(mesh)
#endif
@@ -96,10 +99,11 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
static MVert *dm_getVertArray(DerivedMesh *dm)
{
- MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
if (!mvert) {
- mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, dm->getNumVerts(dm));
+ mvert = (MVert *)CustomData_add_layer(
+ &dm->vertData, CD_MVERT, CD_CALLOC, nullptr, dm->getNumVerts(dm));
CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY);
dm->copyVertArray(dm, mvert);
}
@@ -109,10 +113,11 @@ static MVert *dm_getVertArray(DerivedMesh *dm)
static MEdge *dm_getEdgeArray(DerivedMesh *dm)
{
- MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ MEdge *medge = (MEdge *)CustomData_get_layer(&dm->edgeData, CD_MEDGE);
if (!medge) {
- medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, dm->getNumEdges(dm));
+ medge = (MEdge *)CustomData_add_layer(
+ &dm->edgeData, CD_MEDGE, CD_CALLOC, nullptr, dm->getNumEdges(dm));
CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY);
dm->copyEdgeArray(dm, medge);
}
@@ -122,7 +127,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm)
static MFace *dm_getTessFaceArray(DerivedMesh *dm)
{
- MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
if (!mface) {
int numTessFaces = dm->getNumTessFaces(dm);
@@ -132,10 +137,11 @@ static MFace *dm_getTessFaceArray(DerivedMesh *dm)
* this layer is needed with non-zero size, but currently CD stuff does not check
* for requested layer size on creation and just returns layer which was previously
* added (sergey) */
- return NULL;
+ return nullptr;
}
- mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ mface = (MFace *)CustomData_add_layer(
+ &dm->faceData, CD_MFACE, CD_CALLOC, nullptr, numTessFaces);
CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
dm->copyTessFaceArray(dm, mface);
}
@@ -145,10 +151,11 @@ static MFace *dm_getTessFaceArray(DerivedMesh *dm)
static MLoop *dm_getLoopArray(DerivedMesh *dm)
{
- MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ MLoop *mloop = (MLoop *)CustomData_get_layer(&dm->loopData, CD_MLOOP);
if (!mloop) {
- mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, dm->getNumLoops(dm));
+ mloop = (MLoop *)CustomData_add_layer(
+ &dm->loopData, CD_MLOOP, CD_CALLOC, nullptr, dm->getNumLoops(dm));
CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
dm->copyLoopArray(dm, mloop);
}
@@ -158,10 +165,11 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm)
static MPoly *dm_getPolyArray(DerivedMesh *dm)
{
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ MPoly *mpoly = (MPoly *)CustomData_get_layer(&dm->polyData, CD_MPOLY);
if (!mpoly) {
- mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, dm->getNumPolys(dm));
+ mpoly = (MPoly *)CustomData_add_layer(
+ &dm->polyData, CD_MPOLY, CD_CALLOC, nullptr, dm->getNumPolys(dm));
CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
dm->copyPolyArray(dm, mpoly);
}
@@ -171,7 +179,8 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm)
static MVert *dm_dupVertArray(DerivedMesh *dm)
{
- MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp");
+ MVert *tmp = (MVert *)MEM_malloc_arrayN(
+ dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp");
if (tmp) {
dm->copyVertArray(dm, tmp);
@@ -182,7 +191,8 @@ static MVert *dm_dupVertArray(DerivedMesh *dm)
static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
{
- MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp");
+ MEdge *tmp = (MEdge *)MEM_malloc_arrayN(
+ dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp");
if (tmp) {
dm->copyEdgeArray(dm, tmp);
@@ -193,7 +203,8 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
static MFace *dm_dupFaceArray(DerivedMesh *dm)
{
- MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp");
+ MFace *tmp = (MFace *)MEM_malloc_arrayN(
+ dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp");
if (tmp) {
dm->copyTessFaceArray(dm, tmp);
@@ -204,7 +215,8 @@ static MFace *dm_dupFaceArray(DerivedMesh *dm)
static MLoop *dm_dupLoopArray(DerivedMesh *dm)
{
- MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp");
+ MLoop *tmp = (MLoop *)MEM_malloc_arrayN(
+ dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp");
if (tmp) {
dm->copyLoopArray(dm, tmp);
@@ -215,7 +227,8 @@ static MLoop *dm_dupLoopArray(DerivedMesh *dm)
static MPoly *dm_dupPolyArray(DerivedMesh *dm)
{
- MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp");
+ MPoly *tmp = (MPoly *)MEM_malloc_arrayN(
+ dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp");
if (tmp) {
dm->copyPolyArray(dm, tmp);
@@ -239,14 +252,14 @@ static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm)
looptri = dm->looptris.array;
BLI_rw_mutex_unlock(&loops_cache_lock);
- if (looptri != NULL) {
+ if (looptri != nullptr) {
BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num);
}
else {
BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
- /* We need to ensure array is still NULL inside mutex-protected code,
+ /* We need to ensure array is still nullptr inside mutex-protected code,
* some other thread might have already recomputed those looptris. */
- if (dm->looptris.array == NULL) {
+ if (dm->looptris.array == nullptr) {
dm->recalcLoopTri(dm);
}
looptri = dm->looptris.array;
@@ -343,7 +356,7 @@ void DM_init(DerivedMesh *dm,
DM_init_funcs(dm);
dm->needsFree = 1;
- dm->dirty = 0;
+ dm->dirty = (DMDirtyFlag)0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
@@ -385,7 +398,7 @@ void DM_from_template_ex(DerivedMesh *dm,
DM_init_funcs(dm);
dm->needsFree = 1;
- dm->dirty = 0;
+ dm->dirty = (DMDirtyFlag)0;
}
void DM_from_template(DerivedMesh *dm,
DerivedMesh *source,
@@ -482,7 +495,7 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
const unsigned int totloop = dm->numLoopData;
const int looptris_num = poly_to_tri_count(totpoly, totloop);
- BLI_assert(dm->looptris.array_wip == NULL);
+ BLI_assert(dm->looptris.array_wip == nullptr);
SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip);
@@ -494,8 +507,8 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
if (totpoly) {
- if (dm->looptris.array_wip == NULL) {
- dm->looptris.array_wip = MEM_malloc_arrayN(
+ if (dm->looptris.array_wip == nullptr) {
+ dm->looptris.array_wip = (MLoopTri *)MEM_malloc_arrayN(
looptris_num, sizeof(*dm->looptris.array_wip), __func__);
dm->looptris.num_alloc = looptris_num;
}
@@ -656,7 +669,7 @@ void DM_interp_vert_data(DerivedMesh *source,
int dest_index)
{
CustomData_interp(
- &source->vertData, &dest->vertData, src_indices, weights, NULL, count, dest_index);
+ &source->vertData, &dest->vertData, src_indices, weights, nullptr, count, dest_index);
}
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
@@ -669,7 +682,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
/* these may not really be the orco's, but it's only for preview.
* could be solver better once, but isn't simple */
- orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "BMEditMesh Orco");
+ orco = (float(*)[3])MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "BMEditMesh Orco");
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(orco[i], eve->co);
@@ -702,14 +715,14 @@ static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free)
clmd->sim_parms->shapekey_rest);
if (kb && kb->data) {
- return kb->data;
+ return (float(*)[3])kb->data;
}
}
- return NULL;
+ return nullptr;
}
- return NULL;
+ return nullptr;
}
static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
@@ -719,7 +732,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
int free;
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, me);
}
else {
mesh = BKE_mesh_copy_for_eval(me, true);
@@ -748,10 +761,10 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc
free = 1;
if (mesh_orco->totvert == totvert) {
- orco = BKE_mesh_vert_coords_alloc(mesh_orco, NULL);
+ orco = BKE_mesh_vert_coords_alloc(mesh_orco, nullptr);
}
else {
- orco = BKE_mesh_vert_coords_alloc(mesh, NULL);
+ orco = BKE_mesh_vert_coords_alloc(mesh, nullptr);
}
}
else {
@@ -762,14 +775,14 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc
if (orco) {
if (layer == CD_ORCO) {
- BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
+ BKE_mesh_orco_verts_transform((Mesh *)ob->data, orco, totvert, 0);
}
- if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
- CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
+ if (!(layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer))) {
+ CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, nullptr, mesh->totvert);
BKE_mesh_update_customdata_pointers(mesh, false);
- layerorco = CustomData_get_layer(&mesh->vdata, layer);
+ layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer);
}
memcpy(layerorco, orco, sizeof(float[3]) * totvert);
@@ -797,10 +810,10 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
* (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
if (do_poly_normals) {
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
+ float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
+ &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
BKE_mesh_calc_normals_poly(mesh_final->mvert,
- NULL,
+ nullptr,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->mpoly,
@@ -869,6 +882,56 @@ void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
}
+/**
+ * Modifies the given mesh and geometry set. The geometry set is expect to have NO mesh component.
+ * After this function ends, the geometry set will still have NO mesh component. Instead, an input
+ * mesh is passed separately and is returned separately.
+ *
+ * The purpose of the geometry set is to store all non-mesh geometry components that are generated
+ * by modifiers.
+ */
+static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
+ const ModifierEvalContext &mectx,
+ Object *ob,
+ Mesh *input_mesh,
+ GeometrySet &geometry_set)
+{
+ Mesh *mesh_output = nullptr;
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
+ if (mti->modifyGeometrySet == nullptr) {
+ mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh);
+ }
+ else {
+ /* For performance reasons, this should be called by the modifier and/or nodes themselves at
+ * some point. */
+ BKE_mesh_wrapper_ensure_mdata(input_mesh);
+
+ /* Adds a new mesh component to the geometry set based on the #input_mesh. */
+ BLI_assert(!geometry_set.has<MeshComponent>());
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace(input_mesh, GeometryOwnershipType::Editable);
+ mesh_component.copy_vertex_group_names_from_object(*ob);
+
+ /* Let the modifier change the geometry set. */
+ mti->modifyGeometrySet(md, &mectx, &geometry_set);
+
+ /* Release the mesh from the geometry set again. */
+ if (geometry_set.has<MeshComponent>()) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_output = mesh_component.release();
+ geometry_set.remove<MeshComponent>();
+ }
+
+ /* Return an empty mesh instead of null. */
+ if (mesh_output == nullptr) {
+ mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ BKE_mesh_copy_settings(mesh_output, input_mesh);
+ }
+ }
+
+ return mesh_output;
+}
+
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -880,45 +943,50 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
const bool allow_shared_mesh,
/* return args */
Mesh **r_deform,
- Mesh **r_final)
+ Mesh **r_final,
+ GeometrySet **r_geometry_set)
{
/* Input and final mesh. Final mesh is only created the moment the first
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
- Mesh *mesh_input = ob->data;
- Mesh *mesh_final = NULL;
- Mesh *mesh_deform = NULL;
+ Mesh *mesh_input = (Mesh *)ob->data;
+ Mesh *mesh_final = nullptr;
+ Mesh *mesh_deform = nullptr;
+ /* This geometry set contains the non-mesh data that might be generated by modifiers. */
+ GeometrySet geometry_set_final;
BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
/* Deformed vertex locations array. Deform only modifier need this type of
* float array rather than MVert*. Tracked along with mesh_final as an
* optimization to avoid copying coordinates back and forth if there are
* multiple sequential deform only modifiers. */
- float(*deformed_verts)[3] = NULL;
+ float(*deformed_verts)[3] = nullptr;
int num_deformed_verts = mesh_input->totvert;
bool isPrevDeform = false;
/* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested
* for texturing. */
- Mesh *mesh_orco = NULL;
- Mesh *mesh_orco_cloth = NULL;
+ Mesh *mesh_orco = nullptr;
+ Mesh *mesh_orco_cloth = nullptr;
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
/* Sculpt can skip certain modifiers. */
- const bool has_multires = BKE_sculpt_multires_active(scene, ob) != NULL;
+ const bool has_multires = BKE_sculpt_multires_active(scene, ob) != nullptr;
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
- ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
+ ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0;
+ ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : (ModifierApplyFlag)0;
+ const ModifierEvalContext mectx = {
+ depsgraph, ob, (ModifierApplyFlag)(apply_render | apply_cache)};
+ const ModifierEvalContext mectx_orco = {
+ depsgraph, ob, (ModifierApplyFlag)(apply_render | MOD_APPLY_ORCO)};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
@@ -930,10 +998,10 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* even if the resulting data is not used in a material. Only in object mode.
* TODO: this is broken, not drawn by the drawn manager. */
const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
- ModifierData *previewmd = NULL;
+ ModifierData *previewmd = nullptr;
CustomData_MeshMasks previewmask = {0};
if (do_mod_mcol) {
- /* Find the last active modifier generating a preview, or NULL if none. */
+ /* Find the last active modifier generating a preview, or nullptr if none. */
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
@@ -957,7 +1025,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Apply all leading deform modifiers. */
if (useDeform) {
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
@@ -972,7 +1040,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
deformed_verts = BKE_mesh_vert_coords_alloc(mesh_input, &num_deformed_verts);
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- if (mesh_final == NULL) {
+ if (mesh_final == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
@@ -989,7 +1057,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* grab modifiers until index i */
if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index)) {
- md = NULL;
+ md = nullptr;
break;
}
}
@@ -1009,7 +1077,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Apply all remaining constructive and deforming modifiers. */
bool have_non_onlydeform_modifiers_appled = false;
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
@@ -1069,7 +1137,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
CustomData_MeshMasks mask = {0};
mti->requiredDataMask(ob, md, &mask);
if (mask.vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+ add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO);
}
}
@@ -1092,7 +1160,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* if this is not the last modifier in the stack then recalculate the normals
* to avoid giving bogus normals to the next modifier see: T23673. */
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- if (mesh_final == NULL) {
+ if (mesh_final == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
@@ -1103,7 +1171,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
bool check_for_needs_mapping = false;
/* apply vertex coordinates or build a Mesh as necessary */
- if (mesh_final != NULL) {
+ if (mesh_final != nullptr) {
if (have_non_onlydeform_modifiers_appled == false) {
/* If we only deformed, we won't have initialized #CD_ORIGINDEX.
* as this is the only part of the function that initializes mapping. */
@@ -1137,20 +1205,23 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) {
/* calc */
CustomData_add_layer(
- &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totvert);
+ &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totvert);
CustomData_add_layer(
- &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totedge);
+ &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totedge);
CustomData_add_layer(
- &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totpoly);
+ &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totpoly);
/* Not worth parallelizing this,
* gives less than 0.1% overall speedup in best of best cases... */
- range_vn_i(
- CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), mesh_final->totvert, 0);
- range_vn_i(
- CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), mesh_final->totedge, 0);
- range_vn_i(
- CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), mesh_final->totpoly, 0);
+ range_vn_i((int *)CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX),
+ mesh_final->totvert,
+ 0);
+ range_vn_i((int *)CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX),
+ mesh_final->totedge,
+ 0);
+ range_vn_i((int *)CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX),
+ mesh_final->totpoly,
+ 0);
}
}
@@ -1168,49 +1239,50 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* add cloth rest shape key if needed */
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_CLOTH_ORCO);
+ add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_CLOTH_ORCO);
}
/* add an origspace layer if needed */
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer(
- &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
+ &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop);
mesh_init_origspace(mesh_final);
}
}
- Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
+ Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
+ md, mectx, ob, mesh_final, geometry_set_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
/* if the modifier returned a new mesh, release the old one */
if (mesh_final != mesh_next) {
BLI_assert(mesh_final != mesh_input);
- BKE_id_free(NULL, mesh_final);
+ BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_next;
if (deformed_verts) {
MEM_freeN(deformed_verts);
- deformed_verts = NULL;
+ deformed_verts = nullptr;
}
}
/* create an orco mesh in parallel */
if (nextmask.vmask & CD_MASK_ORCO) {
if (!mesh_orco) {
- mesh_orco = create_orco_mesh(ob, mesh_input, NULL, CD_ORCO);
+ mesh_orco = create_orco_mesh(ob, mesh_input, nullptr, CD_ORCO);
}
nextmask.vmask &= ~CD_MASK_ORCO;
- CustomData_MeshMasks temp_cddata_masks = {
- .vmask = CD_MASK_ORIGINDEX,
- .emask = CD_MASK_ORIGINDEX,
- .fmask = CD_MASK_ORIGINDEX,
- .pmask = CD_MASK_ORIGINDEX,
- };
- if (mti->requiredDataMask != NULL) {
+ CustomData_MeshMasks temp_cddata_masks = {0};
+ temp_cddata_masks.vmask = CD_MASK_ORIGINDEX;
+ temp_cddata_masks.emask = CD_MASK_ORIGINDEX;
+ temp_cddata_masks.fmask = CD_MASK_ORIGINDEX;
+ temp_cddata_masks.pmask = CD_MASK_ORIGINDEX;
+
+ if (mti->requiredDataMask != nullptr) {
mti->requiredDataMask(ob, md, &temp_cddata_masks);
}
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
@@ -1223,7 +1295,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* if the modifier returned a new mesh, release the old one */
if (mesh_orco != mesh_next) {
BLI_assert(mesh_orco != mesh_input);
- BKE_id_free(NULL, mesh_orco);
+ BKE_id_free(nullptr, mesh_orco);
}
mesh_orco = mesh_next;
@@ -1233,7 +1305,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* create cloth orco mesh in parallel */
if (nextmask.vmask & CD_MASK_CLOTH_ORCO) {
if (!mesh_orco_cloth) {
- mesh_orco_cloth = create_orco_mesh(ob, mesh_input, NULL, CD_CLOTH_ORCO);
+ mesh_orco_cloth = create_orco_mesh(ob, mesh_input, nullptr, CD_CLOTH_ORCO);
}
nextmask.vmask &= ~CD_MASK_CLOTH_ORCO;
@@ -1249,7 +1321,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* if the modifier returned a new mesh, release the old one */
if (mesh_orco_cloth != mesh_next) {
BLI_assert(mesh_orco != mesh_input);
- BKE_id_free(NULL, mesh_orco_cloth);
+ BKE_id_free(nullptr, mesh_orco_cloth);
}
mesh_orco_cloth = mesh_next;
@@ -1277,7 +1349,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- BLI_linklist_free((LinkNode *)datamasks, NULL);
+ BLI_linklist_free((LinkNode *)datamasks, nullptr);
for (md = firstmd; md; md = md->next) {
BKE_modifier_free_temporary_data(md);
@@ -1286,11 +1358,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Yay, we are done. If we have a Mesh and deformed vertices,
* we need to apply these back onto the Mesh. If we have no
* Mesh then we need to build one. */
- if (mesh_final == NULL) {
+ if (mesh_final == nullptr) {
/* Note: this check on cdmask is a bit dodgy, it handles the issue at stake here (see T68211),
* but other cases might require similar handling?
* Could be a good idea to define a proper CustomData_MeshMask for that then. */
- if (deformed_verts == NULL && allow_shared_mesh &&
+ if (deformed_verts == nullptr && allow_shared_mesh &&
(final_datamask.lmask & CD_MASK_NORMAL) == 0 &&
(final_datamask.pmask & CD_MASK_NORMAL) == 0) {
mesh_final = mesh_input;
@@ -1302,7 +1374,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
MEM_freeN(deformed_verts);
- deformed_verts = NULL;
+ deformed_verts = nullptr;
}
/* Denotes whether the object which the modifier stack came from owns the mesh or whether the
@@ -1314,19 +1386,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case
* matches input mesh. */
if (is_own_mesh) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+ add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO);
}
if (mesh_deform) {
- add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO);
+ add_orco_mesh(ob, nullptr, mesh_deform, nullptr, CD_ORCO);
}
}
if (mesh_orco) {
- BKE_id_free(NULL, mesh_orco);
+ BKE_id_free(nullptr, mesh_orco);
}
if (mesh_orco_cloth) {
- BKE_id_free(NULL, mesh_orco_cloth);
+ BKE_id_free(nullptr, mesh_orco_cloth);
}
/* Compute normals. */
@@ -1335,16 +1407,16 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else {
Mesh_Runtime *runtime = &mesh_input->runtime;
- if (runtime->mesh_eval == NULL) {
- BLI_assert(runtime->eval_mutex != NULL);
- BLI_mutex_lock(runtime->eval_mutex);
- if (runtime->mesh_eval == NULL) {
+ if (runtime->mesh_eval == nullptr) {
+ BLI_assert(runtime->eval_mutex != nullptr);
+ BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex);
+ if (runtime->mesh_eval == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
mesh_calc_finalize(mesh_input, mesh_final);
runtime->mesh_eval = mesh_final;
}
- BLI_mutex_unlock(runtime->eval_mutex);
+ BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex);
}
mesh_final = runtime->mesh_eval;
}
@@ -1358,6 +1430,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (r_deform) {
*r_deform = mesh_deform;
}
+ if (r_geometry_set) {
+ *r_geometry_set = new GeometrySet(std::move(geometry_set_final));
+ }
}
float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3]
@@ -1369,7 +1444,7 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3]
*r_vert_len = em->bm->totvert;
- cos = MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "vertexcos");
+ cos = (float(*)[3])MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "vertexcos");
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(cos[i], eve->co);
@@ -1383,7 +1458,7 @@ bool editbmesh_modifier_is_enabled(Scene *scene,
ModifierData *md,
bool has_prev_mesh)
{
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
@@ -1417,10 +1492,10 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
* (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
if (do_poly_normals) {
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
+ float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
+ &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
BKE_mesh_calc_normals_poly(mesh_final->mvert,
- NULL,
+ nullptr,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->mpoly,
@@ -1442,7 +1517,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
* check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
* but quiets annoying error messages since tessfaces wont be created. */
if (final_datamask->fmask & CD_MASK_MFACE) {
- if (mesh_final->edit_mesh == NULL) {
+ if (mesh_final->edit_mesh == nullptr) {
BKE_mesh_tessface_ensure(mesh_final);
}
}
@@ -1466,35 +1541,39 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask,
/* return args */
Mesh **r_cage,
- Mesh **r_final)
+ Mesh **r_final,
+ GeometrySet **r_geometry_set)
{
/* Input and final mesh. Final mesh is only created the moment the first
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
- Mesh *mesh_input = ob->data;
- Mesh *mesh_final = NULL;
- Mesh *mesh_cage = NULL;
+ Mesh *mesh_input = (Mesh *)ob->data;
+ Mesh *mesh_final = nullptr;
+ Mesh *mesh_cage = nullptr;
+ /* This geometry set contains the non-mesh data that might be generated by modifiers. */
+ GeometrySet geometry_set_final;
/* Deformed vertex locations array. Deform only modifier need this type of
* float array rather than MVert*. Tracked along with mesh_final as an
* optimization to avoid copying coordinates back and forth if there are
* multiple sequential deform only modifiers. */
- float(*deformed_verts)[3] = NULL;
+ float(*deformed_verts)[3] = nullptr;
int num_deformed_verts = 0;
bool isPrevDeform = false;
/* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested
* for texturing. */
- Mesh *mesh_orco = NULL;
+ Mesh *mesh_orco = nullptr;
/* Modifier evaluation modes. */
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
/* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | apply_render};
+ ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0;
+ const ModifierEvalContext mectx = {
+ depsgraph, ob, (ModifierApplyFlag)(MOD_APPLY_USECACHE | apply_render)};
const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
@@ -1508,24 +1587,24 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
- scene, ob, md, &final_datamask, required_mode, NULL, NULL);
+ scene, ob, md, &final_datamask, required_mode, nullptr, nullptr);
CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
/* Evaluate modifiers up to certain index to get the mesh cage. */
- int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true);
if (r_cage && cageIndex == -1) {
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
- em_input, &final_datamask, NULL, mesh_input);
+ em_input, &final_datamask, nullptr, mesh_input);
}
/* Clear errors before evaluation. */
BKE_modifiers_clear_errors(ob);
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
- if (!editbmesh_modifier_is_enabled(scene, ob, md, mesh_final != NULL)) {
+ if (!editbmesh_modifier_is_enabled(scene, ob, md, mesh_final != nullptr)) {
continue;
}
@@ -1555,11 +1634,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- if (mesh_final == NULL) {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
+ if (mesh_final == nullptr) {
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, nullptr, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
}
- BLI_assert(deformed_verts != NULL);
+ BLI_assert(deformed_verts != nullptr);
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
@@ -1577,7 +1656,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (deformed_verts) {
Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
if (mesh_final != mesh_cage) {
- BKE_id_free(NULL, mesh_final);
+ BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_tmp;
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@@ -1589,8 +1668,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else {
mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
- em_input, NULL, deformed_verts, mesh_input);
- deformed_verts = NULL;
+ em_input, nullptr, deformed_verts, mesh_input);
+ deformed_verts = nullptr;
}
/* create an orco derivedmesh in parallel */
@@ -1612,7 +1691,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (mesh_next) {
/* if the modifier returned a new dm, release the old one */
if (mesh_orco && mesh_orco != mesh_next) {
- BKE_id_free(NULL, mesh_orco);
+ BKE_id_free(nullptr, mesh_orco);
}
mesh_orco = mesh_next;
}
@@ -1632,23 +1711,24 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
CustomData_add_layer(
- &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
+ &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop);
mesh_init_origspace(mesh_final);
}
}
- Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
+ Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
+ md, mectx, ob, mesh_final, geometry_set_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
if (mesh_final && mesh_final != mesh_next) {
- BKE_id_free(NULL, mesh_final);
+ BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_next;
if (deformed_verts) {
MEM_freeN(deformed_verts);
- deformed_verts = NULL;
+ deformed_verts = nullptr;
}
}
mesh_final->runtime.deformed_only = false;
@@ -1668,12 +1748,12 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) {
BKE_mesh_runtime_reset_edit_data(me_orig);
}
- me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
+ me_orig->runtime.edit_data->vertexCos = (float(*)[3])MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
&final_datamask,
- deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
+ deformed_verts ? (float(*)[3])MEM_dupallocN(deformed_verts) : nullptr,
mesh_input);
}
}
@@ -1681,7 +1761,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
}
- BLI_linklist_free((LinkNode *)datamasks, NULL);
+ BLI_linklist_free((LinkNode *)datamasks, nullptr);
/* Yay, we are done. If we have a DerivedMesh and deformed vertices need
* to apply these back onto the DerivedMesh. If we have no DerivedMesh
@@ -1690,7 +1770,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (deformed_verts) {
Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
if (mesh_final != mesh_cage) {
- BKE_id_free(NULL, mesh_final);
+ BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_tmp;
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@@ -1704,7 +1784,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, deformed_verts, mesh_input);
- deformed_verts = NULL;
+ deformed_verts = nullptr;
}
if (deformed_verts) {
@@ -1720,7 +1800,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
if (mesh_orco) {
- BKE_id_free(NULL, mesh_orco);
+ BKE_id_free(nullptr, mesh_orco);
}
/* Ensure normals calculation below is correct. */
@@ -1739,6 +1819,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (r_cage) {
*r_cage = mesh_cage;
}
+ if (r_geometry_set) {
+ *r_geometry_set = new GeometrySet(std::move(geometry_set_final));
+ }
}
static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval)
@@ -1784,7 +1867,8 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
#endif
- Mesh *mesh_eval = NULL, *mesh_deform_eval = NULL;
+ Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr;
+ GeometrySet *geometry_set_eval = nullptr;
mesh_calc_modifiers(depsgraph,
scene,
ob,
@@ -1795,7 +1879,8 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
true,
true,
&mesh_deform_eval,
- &mesh_eval);
+ &mesh_eval,
+ &geometry_set_eval);
/* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result
* is not guaranteed to be owned by object.
@@ -1803,10 +1888,16 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
* Check ownership now, since later on we can not go to a mesh owned by someone else via
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
* the final result might be freed prior to object). */
- Mesh *mesh = ob->data;
+ Mesh *mesh = (Mesh *)ob->data;
const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval);
BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned);
+ /* Add the final mesh as read-only non-owning component to the geometry set. */
+ BLI_assert(!geometry_set_eval->has<MeshComponent>());
+ MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
+ mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly);
+ ob->runtime.geometry_set_eval = geometry_set_eval;
+
ob->runtime.mesh_deform_eval = mesh_deform_eval;
ob->runtime.last_data_mask = *dataMask;
ob->runtime.last_need_mapping = need_mapping;
@@ -1816,7 +1907,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
/* Make sure that drivers can target shapekey properties.
* Note that this causes a potential inconsistency, as the shapekey may have a
* different topology than the evaluated mesh. */
- BLI_assert(mesh->key == NULL || DEG_is_evaluated_id(&mesh->key->id));
+ BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
mesh_eval->key = mesh->key;
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
@@ -1846,11 +1937,14 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
Mesh *me_cage;
Mesh *me_final;
+ GeometrySet *non_mesh_components;
- editbmesh_calc_modifiers(depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final);
+ editbmesh_calc_modifiers(
+ depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
em->mesh_eval_final = me_final;
em->mesh_eval_cage = me_cage;
+ obedit->runtime.geometry_set_eval = non_mesh_components;
BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
@@ -1878,7 +1972,8 @@ static void object_get_datamask(const Depsgraph *depsgraph,
return;
}
- Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
+ Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) :
+ nullptr;
if (DEG_get_original_object(ob) == actob) {
bool editing = BKE_paint_select_face_test(actob);
@@ -1948,7 +2043,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
- if ((mesh_eval == NULL) ||
+ if ((mesh_eval == nullptr) ||
!CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime.last_need_mapping)) {
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
@@ -1957,7 +2052,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
mesh_eval = BKE_object_get_evaluated_mesh(ob);
}
- if (mesh_eval != NULL) {
+ if (mesh_eval != nullptr) {
BLI_assert(!(mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL));
}
return mesh_eval;
@@ -2001,7 +2096,8 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
{
Mesh *final;
- mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, false, NULL, &final);
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final, nullptr);
return final;
}
@@ -2014,7 +2110,8 @@ Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
{
Mesh *final;
- mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, index, false, false, NULL, &final);
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final, nullptr);
return final;
}
@@ -2026,7 +2123,8 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
{
Mesh *final;
- mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, NULL, &final);
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr);
return final;
}
@@ -2038,7 +2136,8 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
{
Mesh *final;
- mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, NULL, &final);
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr);
return final;
}
@@ -2058,7 +2157,7 @@ Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph,
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
+ object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
if (!em->mesh_eval_cage ||
!CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
@@ -2083,7 +2182,7 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
+ object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
if (!em->mesh_eval_cage ||
!CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
@@ -2108,10 +2207,10 @@ Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
/***/
/* same as above but for vert coords */
-typedef struct {
+struct MappedUserData {
float (*vertexcos)[3];
BLI_bitmap *vertex_visit;
-} MappedUserData;
+};
static void make_vertexcos__mapFunc(void *userData,
int index,
@@ -2153,30 +2252,32 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len)
{
- BKE_mesh_calc_loop_tangent_ex(dm->getVertArray(dm),
- dm->getPolyArray(dm),
- dm->getNumPolys(dm),
- dm->getLoopArray(dm),
- dm->getLoopTriArray(dm),
- dm->getNumLoopTri(dm),
- &dm->loopData,
- calc_active_tangent,
- tangent_names,
- tangent_names_len,
- CustomData_get_layer(&dm->polyData, CD_NORMAL),
- dm->getLoopDataArray(dm, CD_NORMAL),
- dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
- /* result */
- &dm->loopData,
- dm->getNumLoops(dm),
- &dm->tangent_mask);
+ BKE_mesh_calc_loop_tangent_ex(
+ dm->getVertArray(dm),
+ dm->getPolyArray(dm),
+ dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm),
+ dm->getNumLoopTri(dm),
+ &dm->loopData,
+ calc_active_tangent,
+ tangent_names,
+ tangent_names_len,
+ (float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL),
+ (float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
+ (float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
+ /* result */
+ &dm->loopData,
+ dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
static void mesh_init_origspace(Mesh *mesh)
{
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
+ OrigSpaceLoop *lof_array = (OrigSpaceLoop *)CustomData_get_layer(&mesh->ldata,
+ CD_ORIGSPACE_MLOOP);
const int numpoly = mesh->totpoly;
// const int numloop = mesh->totloop;
MVert *mv = mesh->mvert;
@@ -2184,8 +2285,7 @@ static void mesh_init_origspace(Mesh *mesh)
MPoly *mp = mesh->mpoly;
int i, j, k;
- float(*vcos_2d)[2] = NULL;
- BLI_array_staticdeclare(vcos_2d, 64);
+ blender::Vector<blender::float2, 64> vcos_2d;
for (i = 0; i < numpoly; i++, mp++) {
OrigSpaceLoop *lof = lof_array + mp->loopstart;
@@ -2206,8 +2306,7 @@ static void mesh_init_origspace(Mesh *mesh)
BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
axis_dominant_v3_to_m3(mat, p_nor);
- BLI_array_clear(vcos_2d);
- BLI_array_reserve(vcos_2d, mp->totloop);
+ vcos_2d.resize(mp->totloop);
for (j = 0; j < mp->totloop; j++, l++) {
mul_v3_m3v3(co, mat, mv[l->v].co);
copy_v2_v2(vcos_2d[j], co);
@@ -2245,7 +2344,6 @@ static void mesh_init_origspace(Mesh *mesh)
}
BKE_mesh_tessface_clear(mesh);
- BLI_array_free(vcos_2d);
}
/* derivedmesh info printing function,
@@ -2367,7 +2465,7 @@ bool DM_is_valid(DerivedMesh *dm)
do_fixes,
&changed);
- is_valid &= BKE_mesh_validate_arrays(NULL,
+ is_valid &= BKE_mesh_validate_arrays(nullptr,
dm->getVertArray(dm),
dm->getNumVerts(dm),
dm->getEdgeArray(dm),
@@ -2378,7 +2476,7 @@ bool DM_is_valid(DerivedMesh *dm)
dm->getNumLoops(dm),
dm->getPolyArray(dm),
dm->getNumPolys(dm),
- dm->getVertDataArray(dm, CD_MDEFORMVERT),
+ (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT),
do_verbose,
do_fixes,
&changed);
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 13abfa92032..633d6202222 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -42,6 +42,7 @@
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "DNA_light_types.h"
+#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 03c812b3b3d..ea41495d097 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1189,7 +1189,7 @@ static void nlaeval_free(NlaEvalData *nlaeval)
/* ---------------------- */
-static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index)
+static int nlaevalchan_validate_index(const NlaEvalChannel *nec, int index)
{
if (nec->is_array) {
if (index >= 0 && index < nec->base_snapshot.length) {
@@ -1201,6 +1201,28 @@ static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index)
return 0;
}
+static bool nlaevalchan_validate_index_ex(const NlaEvalChannel *nec, const int array_index)
+{
+ /** Although array_index comes from fcurve, that doesn't necessarily mean the property has that
+ * many elements. */
+ const int index = nlaevalchan_validate_index(nec, array_index);
+
+ if (index < 0) {
+ if (G.debug & G_DEBUG) {
+ ID *id = nec->key.ptr.owner_id;
+ CLOG_WARN(&LOG,
+ "Animation: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
+ id ? (id->name + 2) : "<No ID>",
+ nec->rna_path,
+ array_index,
+ nec->base_snapshot.length);
+ }
+
+ return false;
+ }
+ return true;
+}
+
/* Initialize default values for NlaEvalChannel from the property data. */
static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values)
{
@@ -1455,7 +1477,7 @@ static float nla_combine_value(
return old_value + (value - base_value) * inf;
case NEC_MIX_MULTIPLY:
- if (base_value == 0.0f) {
+ if (IS_EQF(base_value, 0.0f)) {
base_value = 1.0f;
}
return old_value * powf(value / base_value, inf);
@@ -1471,6 +1493,11 @@ static float nla_combine_value(
static bool nla_invert_blend_value(
int blend_mode, float old_value, float target_value, float influence, float *r_value)
{
+ /** No solution if strip had 0 influence. */
+ if (IS_EQF(influence, 0.0f)) {
+ return false;
+ }
+
switch (blend_mode) {
case NLASTRIP_MODE_ADD:
*r_value = (target_value - old_value) / influence;
@@ -1481,9 +1508,9 @@ static bool nla_invert_blend_value(
return true;
case NLASTRIP_MODE_MULTIPLY:
- if (old_value == 0.0f) {
+ if (IS_EQF(old_value, 0.0f)) {
/* Resolve 0/0 to 1. */
- if (target_value == 0.0f) {
+ if (IS_EQF(target_value, 0.0f)) {
*r_value = 1.0f;
return true;
}
@@ -1514,6 +1541,11 @@ static bool nla_invert_combine_value(int mix_mode,
float influence,
float *r_value)
{
+ /* No solution if strip had no influence. */
+ if (IS_EQF(influence, 0.0f)) {
+ return false;
+ }
+
switch (mix_mode) {
case NEC_MIX_ADD:
case NEC_MIX_AXIS_ANGLE:
@@ -1521,12 +1553,12 @@ static bool nla_invert_combine_value(int mix_mode,
return true;
case NEC_MIX_MULTIPLY:
- if (base_value == 0.0f) {
+ if (IS_EQF(base_value, 0.0f)) {
base_value = 1.0f;
}
- if (old_value == 0.0f) {
+ if (IS_EQF(old_value, 0.0f)) {
/* Resolve 0/0 to 1. */
- if (target_value == 0.0f) {
+ if (IS_EQF(target_value, 0.0f)) {
*r_value = base_value;
return true;
}
@@ -1560,11 +1592,14 @@ static void nla_combine_quaternion(const float old_values[4],
}
/* invert accumulation of quaternion channels for Combine mode according to influence */
-static void nla_invert_combine_quaternion(const float old_values[4],
+static bool nla_invert_combine_quaternion(const float old_values[4],
const float values[4],
float influence,
float result[4])
{
+ if (IS_EQF(influence, 0.0f)) {
+ return false;
+ }
float tmp_old[4], tmp_new[4];
normalize_qt_qt(tmp_old, old_values);
@@ -1573,6 +1608,8 @@ static void nla_invert_combine_quaternion(const float old_values[4],
mul_qt_qtqt(result, tmp_old, tmp_new);
pow_qt_fl_normalized(result, 1.0f / influence);
+
+ return true;
}
/* Data about the current blend mode. */
@@ -1612,19 +1649,7 @@ static bool nlaeval_blend_value(NlaBlendData *blend,
return false;
}
- int index = nlaevalchan_validate_index(nec, array_index);
-
- if (index < 0) {
- if (G.debug & G_DEBUG) {
- ID *id = nec->key.ptr.owner_id;
- CLOG_WARN(&LOG,
- "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
- id ? (id->name + 2) : "<No ID>",
- nec->rna_path,
- array_index,
- nec->base_snapshot.length);
- }
-
+ if (!nlaevalchan_validate_index_ex(nec, array_index)) {
return false;
}
@@ -1633,21 +1658,21 @@ static bool nlaeval_blend_value(NlaBlendData *blend,
BLI_bitmap_set_all(nec->valid.ptr, true, 4);
}
else {
- BLI_BITMAP_ENABLE(nec->valid.ptr, index);
+ BLI_BITMAP_ENABLE(nec->valid.ptr, array_index);
}
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
- float *p_value = &nec_snapshot->values[index];
+ float *p_value = &nec_snapshot->values[array_index];
if (blend->mode == NLASTRIP_MODE_COMBINE) {
/* Quaternion blending is deferred until all sub-channel values are known. */
if (nec->mix_mode == NEC_MIX_QUATERNION) {
NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec);
- blend_snapshot->values[index] = value;
+ blend_snapshot->values[array_index] = value;
}
else {
- float base_value = nec->base_snapshot.values[index];
+ float base_value = nec->base_snapshot.values[array_index];
*p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence);
}
@@ -2502,7 +2527,9 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
*r_force_all = true;
- nla_invert_combine_quaternion(old_values, values, influence, values);
+ if (!nla_invert_combine_quaternion(old_values, values, influence, values)) {
+ return false;
+ }
}
else {
float *base_values = nec->base_snapshot.values;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b1462167edd..ae0c27635a6 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -36,6 +36,8 @@
#include "BKE_appdir.h" /* own include */
#include "BKE_blender_version.h"
+#include "BLT_translation.h"
+
#include "GHOST_Path-api.h"
#include "MEM_guardedalloc.h"
@@ -146,47 +148,74 @@ static char *blender_version_decimal(const int version)
* \{ */
/**
- * This is now only used to really get the user's default document folder.
+ * Get the folder that's the "natural" starting point for browsing files on an OS. On Unix that is
+ * $HOME, on Windows it is %userprofile%/Documents.
*
- * \note On Windows `Users/{MyUserName}/Documents` is used
- * as it's the default location to save documents.
+ * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
+ * documents.
*/
const char *BKE_appdir_folder_default(void)
{
#ifndef WIN32
- const char *const xdg_documents_dir = BLI_getenv("XDG_DOCUMENTS_DIR");
+ return BLI_getenv("HOME");
+#else /* Windows */
+ static char documentfolder[MAXPATHLEN];
- if (xdg_documents_dir) {
- return xdg_documents_dir;
+ if (BKE_appdir_folder_documents(documentfolder)) {
+ return documentfolder;
}
+ return NULL;
+#endif /* WIN32 */
+}
+
+/**
+ * Get the user's home directory, i.e. $HOME on UNIX, %userprofile% on Windows.
+ */
+const char *BKE_appdir_folder_home(void)
+{
+#ifndef WIN32
return BLI_getenv("HOME");
-#else /* Windows */
- static char documentfolder[MAXPATHLEN];
- HRESULT hResult;
+#else /* Windows */
+ return BLI_getenv("userprofile");
+#endif
+}
- /* Check for `%HOME%` environment variable. */
- if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) {
- if (BLI_is_dir(documentfolder)) {
- return documentfolder;
- }
+/**
+ * Get the user's document directory, i.e. $HOME/Documents on Linux, %userprofile%/Documents on
+ * Windows. If this can't be found using OS queries (via Ghost), try manually finding it.
+ *
+ * \returns True if the path is valid and points to an existing directory.
+ */
+bool BKE_appdir_folder_documents(char *dir)
+{
+ dir[0] = '\0';
+
+ const char *documents_path = (const char *)GHOST_getUserSpecialDir(
+ GHOST_kUserSpecialDirDocuments);
+
+ /* Usual case: Ghost gave us the documents path. We're done here. */
+ if (documents_path && BLI_is_dir(documents_path)) {
+ BLI_strncpy(dir, documents_path, FILE_MAXDIR);
+ return true;
}
- /* Add user profile support for WIN 2K / NT.
- * This is `%APPDATA%`, which translates to either:
- * - `%USERPROFILE%\Application Data` or...
- * - `%USERPROFILE%\AppData\Roaming` (since Vista).
- */
- hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
+ /* Ghost couldn't give us a documents path, let's try if we can find it ourselves.*/
- if (hResult == S_OK) {
- if (BLI_is_dir(documentfolder)) {
- return documentfolder;
- }
+ const char *home_path = BKE_appdir_folder_home();
+ if (!home_path || !BLI_is_dir(home_path)) {
+ return false;
}
- return NULL;
-#endif /* WIN32 */
+ char try_documents_path[FILE_MAXDIR];
+ /* Own attempt at getting a valid Documents path. */
+ BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL);
+ if (!BLI_is_dir(try_documents_path)) {
+ return false;
+ }
+
+ BLI_strncpy(dir, try_documents_path, FILE_MAXDIR);
+ return true;
}
/**
@@ -877,14 +906,20 @@ bool BKE_appdir_program_python_search(char *fullpath,
const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
#endif
const char *basename = "python";
+#if defined(WIN32) && !defined(NDEBUG)
+ const char *basename_debug = "python_d";
+#endif
char python_version[16];
/* Check both possible names. */
const char *python_names[] = {
#ifdef PYTHON_EXECUTABLE_NAME
- python_build_def,
+ python_build_def,
+#endif
+#if defined(WIN32) && !defined(NDEBUG)
+ basename_debug,
#endif
- python_version,
- basename,
+ python_version,
+ basename,
};
bool is_found = false;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 92146082557..ced211b1926 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2441,7 +2441,7 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
}
/**
- * \param r_last_visited_bone_p the last bone handled by the last call to this function.
+ * \param r_last_visited_bone_p: The last bone handled by the last call to this function.
*/
static int rebuild_pose_bone(
bPose *pose, Bone *bone, bPoseChannel *parchan, int counter, Bone **r_last_visited_bone_p)
diff --git a/source/blender/blenkernel/intern/asset.c b/source/blender/blenkernel/intern/asset.c
new file mode 100644
index 00000000000..7ccb0aa2b57
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset.c
@@ -0,0 +1,151 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_asset.h"
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+
+#include "DNA_ID.h"
+#include "DNA_asset_types.h"
+#include "DNA_defaults.h"
+
+#include "BLO_read_write.h"
+
+#include "MEM_guardedalloc.h"
+
+AssetMetaData *BKE_asset_metadata_create(void)
+{
+ AssetMetaData *asset_data = MEM_callocN(sizeof(*asset_data), __func__);
+ memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data));
+ return asset_data;
+}
+
+void BKE_asset_metadata_free(AssetMetaData **asset_data)
+{
+ if ((*asset_data)->properties) {
+ IDP_FreeProperty((*asset_data)->properties);
+ }
+ MEM_SAFE_FREE((*asset_data)->description);
+ BLI_freelistN(&(*asset_data)->tags);
+
+ MEM_SAFE_FREE(*asset_data);
+}
+
+static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name)
+{
+ AssetTag *tag = MEM_callocN(sizeof(*tag), __func__);
+ BLI_strncpy(tag->name, name, sizeof(tag->name));
+
+ BLI_addtail(&asset_data->tags, tag);
+ asset_data->tot_tags++;
+ /* Invariant! */
+ BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
+
+ return tag;
+}
+
+AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name)
+{
+ AssetTag *tag = asset_metadata_tag_add(asset_data, name);
+ BLI_uniquename(&asset_data->tags, tag, name, '.', offsetof(AssetTag, name), sizeof(tag->name));
+ return tag;
+}
+
+/**
+ * Make sure there is a tag with name \a name, create one if needed.
+ */
+struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data,
+ const char *name)
+{
+ struct AssetTagEnsureResult result = {.tag = NULL};
+ if (!name[0]) {
+ return result;
+ }
+
+ AssetTag *tag = BLI_findstring(&asset_data->tags, name, offsetof(AssetTag, name));
+
+ if (tag) {
+ result.tag = tag;
+ result.is_new = false;
+ return result;
+ }
+
+ tag = asset_metadata_tag_add(asset_data, name);
+
+ result.tag = tag;
+ result.is_new = true;
+ return result;
+}
+
+void BKE_asset_metadata_tag_remove(AssetMetaData *asset_data, AssetTag *tag)
+{
+ BLI_assert(BLI_findindex(&asset_data->tags, tag) >= 0);
+ BLI_freelinkN(&asset_data->tags, tag);
+ asset_data->tot_tags--;
+ /* Invariant! */
+ BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
+}
+
+/* Queries -------------------------------------------- */
+
+PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data),
+ const ID *id)
+{
+ return BKE_previewimg_id_get(id);
+}
+
+/* .blend file API -------------------------------------------- */
+
+void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
+{
+ BLO_write_struct(writer, AssetMetaData, asset_data);
+
+ if (asset_data->properties) {
+ IDP_BlendWrite(writer, asset_data->properties);
+ }
+
+ if (asset_data->description) {
+ BLO_write_string(writer, asset_data->description);
+ }
+ LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) {
+ BLO_write_struct(writer, AssetTag, tag);
+ }
+}
+
+void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
+{
+ /* asset_data itself has been read already. */
+
+ if (asset_data->properties) {
+ BLO_read_data_address(reader, &asset_data->properties);
+ IDP_BlendDataRead(reader, &asset_data->properties);
+ }
+
+ BLO_read_data_address(reader, &asset_data->description);
+ BLO_read_list(reader, &asset_data->tags);
+ BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
+}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index d79168d5443..934beb8a848 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -392,6 +392,8 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty
return &CPPType::get<int>();
case CD_PROP_COLOR:
return &CPPType::get<Color4f>();
+ case CD_PROP_BOOL:
+ return &CPPType::get<bool>();
default:
return nullptr;
}
@@ -415,6 +417,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
if (type.is<Color4f>()) {
return CD_PROP_COLOR;
}
+ if (type.is<bool>()) {
+ return CD_PROP_BOOL;
+ }
return static_cast<CustomDataType>(-1);
}
@@ -449,6 +454,9 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom
case CD_PROP_COLOR:
return std::make_unique<ArrayReadAttribute<Color4f>>(
domain, Span(static_cast<Color4f *>(layer.data), size));
+ case CD_PROP_BOOL:
+ return std::make_unique<ArrayReadAttribute<bool>>(
+ domain, Span(static_cast<bool *>(layer.data), size));
}
}
}
@@ -490,6 +498,9 @@ static WriteAttributePtr write_attribute_from_custom_data(
case CD_PROP_COLOR:
return std::make_unique<ArrayWriteAttribute<Color4f>>(
domain, MutableSpan(static_cast<Color4f *>(layer.data), size));
+ case CD_PROP_BOOL:
+ return std::make_unique<ArrayWriteAttribute<bool>>(
+ domain, MutableSpan(static_cast<bool *>(layer.data), size));
}
}
}
@@ -590,6 +601,15 @@ Set<std::string> GeometryComponent::attribute_names() const
return {};
}
+bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
+{
+ ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ if (attribute) {
+ return true;
+ }
+ return false;
+}
+
static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
const blender::fn::CPPType &to_type)
{
@@ -640,6 +660,28 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return attribute;
}
+ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name,
+ const AttributeDomain domain) const
+{
+ if (!this->attribute_domain_supported(domain)) {
+ return {};
+ }
+
+ ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ if (!attribute) {
+ return {};
+ }
+
+ if (attribute->domain() != domain) {
+ attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
+ if (!attribute) {
+ return {};
+ }
+ }
+
+ return attribute;
+}
+
ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
@@ -742,6 +784,7 @@ bool PointCloudComponent::attribute_domain_with_type_supported(
const AttributeDomain domain, const CustomDataType data_type) const
{
return domain == ATTR_DOMAIN_POINT && ELEM(data_type,
+ CD_PROP_BOOL,
CD_PROP_FLOAT,
CD_PROP_FLOAT2,
CD_PROP_FLOAT3,
@@ -865,8 +908,13 @@ bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain d
if (!this->attribute_domain_supported(domain)) {
return false;
}
- return ELEM(
- data_type, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
+ return ELEM(data_type,
+ CD_PROP_BOOL,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_INT32,
+ CD_PROP_COLOR);
}
int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index f4f25c3a153..5b5bd416ef2 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -296,6 +296,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
}
BLI_freelistN(&userdef->autoexec_paths);
+ BLI_freelistN(&userdef->asset_libraries);
BLI_freelistN(&userdef->uistyles);
BLI_freelistN(&userdef->uifonts);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 567773507cf..0855db1a943 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -52,6 +52,7 @@
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_preferences.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -645,6 +646,8 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
/* Default studio light. */
BKE_studiolight_default(userdef->light_param, userdef->light_ambient);
+ BKE_preferences_asset_library_default_add(userdef);
+
return userdef;
}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 96bf9fbe8d2..e69173cc1d5 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -39,6 +39,7 @@
#include "BKE_collision.h"
#include "BKE_effect.h"
#include "BKE_particle.h"
+#include "BLI_kdopbvh.h"
#include "BKE_modifier.h"
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 96791aed2c3..9a954a89cad 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -23,6 +23,7 @@
#include "DNA_brush_types.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -1833,6 +1834,14 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
break;
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->hardness = 0.7f;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SMOOTHER;
+ break;
default:
break;
}
@@ -1897,6 +1906,7 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_MASK:
case SCULPT_TOOL_DRAW_FACE_SETS:
case SCULPT_TOOL_DISPLACEMENT_ERASER:
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
br->add_col[0] = 0.75f;
br->add_col[1] = 0.75f;
br->add_col[2] = 0.75f;
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 5eec788255d..b86b59066d6 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1773,6 +1773,15 @@ static void layer_collection_flags_store(Main *bmain,
}
}
+static void layer_collection_flags_free_recursive(LayerCollectionFlag *flag)
+{
+ LISTBASE_FOREACH (LayerCollectionFlag *, child, &flag->children) {
+ layer_collection_flags_free_recursive(child);
+ }
+
+ BLI_freelistN(&flag->children);
+}
+
static void layer_collection_flags_restore_recursive(LayerCollection *layer_collection,
LayerCollectionFlag *flag)
{
@@ -1788,7 +1797,6 @@ static void layer_collection_flags_restore_recursive(LayerCollection *layer_coll
child_flag = child_flag->next;
}
- BLI_freelistN(&flag->children);
/* We treat exclude as a special case.
*
@@ -1814,10 +1822,15 @@ static void layer_collection_flags_restore(ListBase *flags, const Collection *co
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(
view_layer, collection);
- /* The flags should only be added if the collection is in the view layer. */
- BLI_assert(layer_collection != NULL);
-
- layer_collection_flags_restore_recursive(layer_collection, flag);
+ /* Check that the collection is still in the scene (and therefore its view layers). In most
+ * cases this is true, but if we move a sub-collection shared by several scenes to a collection
+ * local to the target scene, it is effectively removed from every other scene's hierarchy
+ * (e.g. moving into current scene's master collection). Then the other scene's view layers
+ * won't contain a matching layer collection anymore, so there is nothing to restore to. */
+ if (layer_collection != NULL) {
+ layer_collection_flags_restore_recursive(layer_collection, flag);
+ }
+ layer_collection_flags_free_recursive(flag);
}
BLI_freelistN(flags);
@@ -1877,7 +1890,7 @@ bool BKE_collection_move(Main *bmain,
/* Create and remove layer collections. */
BKE_main_collection_sync(bmain);
- /* Restore the original layer collection flags. */
+ /* Restore the original layer collection flags and free their temporary storage. */
if (do_flag_sync) {
layer_collection_flags_restore(&layer_flags, collection);
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 1c17692ac36..b6f84dfc42f 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -5960,7 +5960,7 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
* Check whether given constraint is not local (i.e. from linked data) when the object is a library
* override.
*
- * \param con May be NULL, in which case we consider it as a non-local constraint case.
+ * \param con: May be NULL, in which case we consider it as a non-local constraint case.
*/
bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstraint *con)
{
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index a1edfd1c56d..65accc66084 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -123,7 +123,7 @@ void CTX_free(bContext *C)
/* store */
-bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr)
+bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr)
{
/* ensure we have a context to put the entry in, if it was already used
* we have to copy the context to ensure */
@@ -178,6 +178,11 @@ bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
return ctx;
}
+bContextStore *CTX_store_get(bContext *C)
+{
+ return C->wm.store;
+}
+
void CTX_store_set(bContext *C, bContextStore *store)
{
C->wm.store = store;
@@ -1202,6 +1207,11 @@ ToolSettings *CTX_data_tool_settings(const bContext *C)
return NULL;
}
+int CTX_data_selected_ids(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "selected_ids", list);
+}
+
int CTX_data_selected_nodes(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_nodes", list);
diff --git a/source/blender/blenkernel/intern/cryptomatte.c b/source/blender/blenkernel/intern/cryptomatte.c
deleted file mode 100644
index 6570ffce920..00000000000
--- a/source/blender/blenkernel/intern/cryptomatte.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#include "BKE_cryptomatte.h"
-
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_compiler_attrs.h"
-#include "BLI_hash_mm3.h"
-#include "BLI_string.h"
-#include <string.h>
-
-static uint32_t cryptomatte_hash(const ID *id)
-{
- const char *name = &id->name[2];
- const int len = BLI_strnlen(name, MAX_NAME - 2);
- uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, len, 0);
- return cryptohash_int;
-}
-
-uint32_t BKE_cryptomatte_object_hash(const Object *object)
-{
- return cryptomatte_hash(&object->id);
-}
-
-uint32_t BKE_cryptomatte_material_hash(const Material *material)
-{
- if (material == NULL) {
- return 0.0f;
- }
- return cryptomatte_hash(&material->id);
-}
-
-uint32_t BKE_cryptomatte_asset_hash(const Object *object)
-{
- const Object *asset_object = object;
- while (asset_object->parent != NULL) {
- asset_object = asset_object->parent;
- }
- return cryptomatte_hash(&asset_object->id);
-}
-
-/* Convert a cryptomatte hash to a float.
- *
- * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
- * cryptomatte specification. See Floating point conversion section in
- * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
- *
- * The conversion uses as many 32 bit floating point values as possible to minimize hash
- * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic.
- *
- * Note that this conversion assumes to be running on a L-endian system. */
-float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
-{
- uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1);
- uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1);
- exponent = MAX2(exponent, (uint32_t)1);
- exponent = MIN2(exponent, (uint32_t)254);
- exponent = exponent << 23;
- uint32_t sign = (cryptomatte_hash >> 31);
- sign = sign << 31;
- uint32_t float_bits = sign | exponent | mantissa;
- float f;
- memcpy(&f, &float_bits, sizeof(uint32_t));
- return f;
-}
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
new file mode 100644
index 00000000000..4bbeb088628
--- /dev/null
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -0,0 +1,190 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_cryptomatte.h"
+#include "BKE_main.h"
+
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_dynstr.h"
+#include "BLI_hash_mm3.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <cstring>
+#include <sstream>
+#include <string>
+
+static uint32_t cryptomatte_hash(const ID *id)
+{
+ const char *name = &id->name[2];
+ const int name_len = BLI_strnlen(name, MAX_NAME);
+ uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len);
+ return cryptohash_int;
+}
+
+uint32_t BKE_cryptomatte_hash(const char *name, int name_len)
+{
+ uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
+ return cryptohash_int;
+}
+
+uint32_t BKE_cryptomatte_object_hash(const Object *object)
+{
+ return cryptomatte_hash(&object->id);
+}
+
+uint32_t BKE_cryptomatte_material_hash(const Material *material)
+{
+ if (material == nullptr) {
+ return 0.0f;
+ }
+ return cryptomatte_hash(&material->id);
+}
+
+uint32_t BKE_cryptomatte_asset_hash(const Object *object)
+{
+ const Object *asset_object = object;
+ while (asset_object->parent != nullptr) {
+ asset_object = asset_object->parent;
+ }
+ return cryptomatte_hash(&asset_object->id);
+}
+
+/* Convert a cryptomatte hash to a float.
+ *
+ * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
+ * cryptomatte specification. See Floating point conversion section in
+ * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
+ *
+ * The conversion uses as many 32 bit floating point values as possible to minimize hash
+ * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic.
+ *
+ * Note that this conversion assumes to be running on a L-endian system. */
+float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
+{
+ uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1);
+ uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1);
+ exponent = MAX2(exponent, (uint32_t)1);
+ exponent = MIN2(exponent, (uint32_t)254);
+ exponent = exponent << 23;
+ uint32_t sign = (cryptomatte_hash >> 31);
+ sign = sign << 31;
+ uint32_t float_bits = sign | exponent | mantissa;
+ float f;
+ memcpy(&f, &float_bits, sizeof(uint32_t));
+ return f;
+}
+
+static ID *cryptomatte_find_id(const ListBase *ids, const float encoded_hash)
+{
+ LISTBASE_FOREACH (ID *, id, ids) {
+ uint32_t hash = BKE_cryptomatte_hash((id->name + 2), BLI_strnlen(id->name + 2, MAX_NAME));
+ if (BKE_cryptomatte_hash_to_float(hash) == encoded_hash) {
+ return id;
+ }
+ }
+ return nullptr;
+}
+
+/* Find an ID in the given main that matches the given encoded float. */
+static struct ID *BKE_cryptomatte_find_id(const Main *bmain, const float encoded_hash)
+{
+ ID *result;
+ result = cryptomatte_find_id(&bmain->objects, encoded_hash);
+ if (result == nullptr) {
+ result = cryptomatte_find_id(&bmain->materials, encoded_hash);
+ }
+ return result;
+}
+
+char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
+{
+ DynStr *matte_id = BLI_dynstr_new();
+ bool first = true;
+ LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
+ if (!first) {
+ BLI_dynstr_append(matte_id, ",");
+ }
+ if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) {
+ BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
+ }
+ else {
+ BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
+ }
+ first = false;
+ }
+ char *result = BLI_dynstr_get_cstring(matte_id);
+ BLI_dynstr_free(matte_id);
+ return result;
+}
+
+void BKE_cryptomatte_matte_id_to_entries(const Main *bmain,
+ NodeCryptomatte *node_storage,
+ const char *matte_id)
+{
+ BLI_freelistN(&node_storage->entries);
+
+ std::istringstream ss(matte_id);
+ while (ss.good()) {
+ CryptomatteEntry *entry = nullptr;
+ std::string token;
+ getline(ss, token, ',');
+ /* Ignore empty tokens. */
+ if (token.length() > 0) {
+ size_t first = token.find_first_not_of(' ');
+ size_t last = token.find_last_not_of(' ');
+ if (first == std::string::npos || last == std::string::npos) {
+ break;
+ }
+ token = token.substr(first, (last - first + 1));
+ if (*token.begin() == '<' && *(--token.end()) == '>') {
+ float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
+ entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry->encoded_hash = encoded_hash;
+ if (bmain) {
+ ID *id = BKE_cryptomatte_find_id(bmain, encoded_hash);
+ if (id != nullptr) {
+ BLI_strncpy(entry->name, id->name + 2, sizeof(entry->name));
+ }
+ }
+ }
+ else {
+ const char *name = token.c_str();
+ int name_len = token.length();
+ entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ BLI_strncpy(entry->name, name, sizeof(entry->name));
+ uint32_t hash = BKE_cryptomatte_hash(name, name_len);
+ entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash);
+ }
+ }
+ if (entry != nullptr) {
+ BLI_addtail(&node_storage->entries, entry);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index fdb3e246382..1e2bc570c65 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1837,6 +1837,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerMultiply_propfloat2,
NULL,
layerAdd_propfloat2},
+ /* 50: CD_PROP_POOL */
+ {sizeof(bool),
+ "bool",
+ 1,
+ N_("Boolean"),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -1892,6 +1907,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropCol",
"CDPropFloat3",
"CDPropFloat2",
+ "CDPropBoolean",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index b56a15b3d45..e18b2d87459 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -42,6 +42,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 9431915b4e4..df1dbaa905f 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -125,11 +125,17 @@ static void vfont_free_data(ID *id)
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
VFont *vf = (VFont *)id;
- if (vf->id.us > 0 || BLO_write_is_undo(writer)) {
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (vf->id.us > 0 || is_undo) {
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
vf->data = NULL;
vf->temp_pf = NULL;
+ /* Do not store packed files in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) {
+ vf->packedfile = NULL;
+ }
+
/* write LibData */
BLO_write_id_struct(writer, VFont, id_address, &vf->id);
BKE_id_blend_write(writer, &vf->id);
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 28695d769d3..e6a67b191f8 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -460,31 +460,54 @@ GeometryComponent *InstancesComponent::copy() const
new_component->positions_ = positions_;
new_component->rotations_ = rotations_;
new_component->scales_ = scales_;
- new_component->objects_ = objects_;
+ new_component->instanced_data_ = instanced_data_;
return new_component;
}
void InstancesComponent::clear()
{
- objects_.clear();
+ instanced_data_.clear();
positions_.clear();
rotations_.clear();
scales_.clear();
}
-void InstancesComponent::add_instance(const Object *object,
+
+void InstancesComponent::add_instance(Object *object,
+ blender::float3 position,
+ blender::float3 rotation,
+ blender::float3 scale)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_OBJECT;
+ data.data.object = object;
+ this->add_instance(data, position, rotation, scale);
+}
+
+void InstancesComponent::add_instance(Collection *collection,
+ blender::float3 position,
+ blender::float3 rotation,
+ blender::float3 scale)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_COLLECTION;
+ data.data.collection = collection;
+ this->add_instance(data, position, rotation, scale);
+}
+
+void InstancesComponent::add_instance(InstancedData data,
blender::float3 position,
blender::float3 rotation,
blender::float3 scale)
{
- objects_.append(object);
+ instanced_data_.append(data);
positions_.append(position);
rotations_.append(rotation);
scales_.append(scale);
}
-Span<const Object *> InstancesComponent::objects() const
+Span<InstancedData> InstancesComponent::instanced_data() const
{
- return objects_;
+ return instanced_data_;
}
Span<float3> InstancesComponent::positions() const
@@ -509,8 +532,11 @@ MutableSpan<float3> InstancesComponent::positions()
int InstancesComponent::instances_amount() const
{
- BLI_assert(positions_.size() == objects_.size());
- return objects_.size();
+ const int size = instanced_data_.size();
+ BLI_assert(positions_.size() == size);
+ BLI_assert(rotations_.size() == size);
+ BLI_assert(scales_.size() == size);
+ return size;
}
bool InstancesComponent::is_empty() const
@@ -538,7 +564,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set,
float (**r_positions)[3],
float (**r_rotations)[3],
float (**r_scales)[3],
- Object ***r_objects)
+ InstancedData **r_instanced_data)
{
const InstancesComponent *component = geometry_set->get_component_for_read<InstancesComponent>();
if (component == nullptr) {
@@ -547,7 +573,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set,
*r_positions = (float(*)[3])component->positions().data();
*r_rotations = (float(*)[3])component->rotations().data();
*r_scales = (float(*)[3])component->scales().data();
- *r_objects = (Object **)component->objects().data();
+ *r_instanced_data = (InstancedData *)component->instanced_data().data();
return component->instances_amount();
}
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 8cc11468771..be14d74de7a 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -36,8 +36,11 @@
#include "BLT_translation.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
#include "BKE_collection.h"
#include "BKE_context.h"
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index fc74439fd76..981f5d50353 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
+#include "BLI_heap.h"
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
@@ -41,6 +42,7 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
@@ -3224,4 +3226,197 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime);
}
}
+
+/* Stroke Uniform Subdivide ------------------------------------- */
+
+typedef struct tSamplePoint {
+ struct tSamplePoint *next, *prev;
+ float x, y, z;
+ float pressure, strength, time;
+ float vertex_color[4];
+ struct MDeformWeight *dw;
+ int totweight;
+} tSamplePoint;
+
+typedef struct tSampleEdge {
+ float length_sq;
+ tSamplePoint *from;
+ tSamplePoint *to;
+} tSampleEdge;
+
+/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */
+static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert)
+{
+ tSamplePoint *new_pt = MEM_callocN(sizeof(tSamplePoint), __func__);
+ copy_v3_v3(&new_pt->x, &pt->x);
+ new_pt->pressure = pt->pressure;
+ new_pt->strength = pt->strength;
+ new_pt->time = pt->time;
+ copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color);
+ if (dvert != NULL) {
+ new_pt->totweight = dvert->totweight;
+ new_pt->dw = MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__);
+ for (uint i = 0; i < new_pt->totweight; ++i) {
+ MDeformWeight *dw = &new_pt->dw[i];
+ MDeformWeight *dw_from = &dvert->dw[i];
+ dw->def_nr = dw_from->def_nr;
+ dw->weight = dw_from->weight;
+ }
+ }
+ return new_pt;
+}
+
+/* Helper: creates a tSampleEdge from two tSamplePoints. Also calculates the length (squared) of
+ * the edge. */
+static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to)
+{
+ tSampleEdge *new_edge = MEM_callocN(sizeof(tSampleEdge), __func__);
+ new_edge->from = from;
+ new_edge->to = to;
+ new_edge->length_sq = len_squared_v3v3(&from->x, &to->x);
+ return new_edge;
+}
+
+/**
+ * Subdivide the grease pencil stroke so the number of points is target_number.
+ * Does not change the shape of the stroke. The new points will be distributed as
+ * uniformly as possible by repeatedly subdividing the current longest edge.
+ *
+ * \param gps: The stroke to be up-sampled.
+ * \param target_number: The number of points the up-sampled stroke should have.
+ * \param select: Select/Deselect the stroke.
+ */
+void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
+ bGPDstroke *gps,
+ const uint32_t target_number,
+ const bool select)
+{
+ /* Stroke needs at least two points and strictly less points than the target number. */
+ if (gps == NULL || gps->totpoints < 2 || gps->totpoints >= target_number) {
+ return;
+ }
+
+ const int totpoints = gps->totpoints;
+ const bool has_dverts = (gps->dvert != NULL);
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC);
+
+ ListBase points = {NULL, NULL};
+ Heap *edges = BLI_heap_new();
+
+ /* Add all points into list. */
+ for (uint32_t i = 0; i < totpoints; ++i) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = has_dverts ? &gps->dvert[i] : NULL;
+ tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert);
+ BLI_addtail(&points, sp);
+ }
+
+ /* Iterate over edges and insert them into the heap. */
+ for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != NULL; pt = pt->next) {
+ tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt);
+ /* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the
+ * negative of the squared length. */
+ BLI_heap_insert(edges, -(se->length_sq), se);
+ }
+
+ if (is_cyclic) {
+ tSamplePoint *sp_first = points.first;
+ tSamplePoint *sp_last = points.last;
+ tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first);
+ BLI_heap_insert(edges, -(se->length_sq), se);
+ }
+
+ int num_points_needed = target_number - totpoints;
+ BLI_assert(num_points_needed > 0);
+
+ while (num_points_needed > 0) {
+ tSampleEdge *se = BLI_heap_pop_min(edges);
+ tSamplePoint *sp = se->from;
+ tSamplePoint *sp_next = se->to;
+
+ /* Subdivide the edge. */
+ tSamplePoint *new_sp = MEM_callocN(sizeof(tSamplePoint), __func__);
+ interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f);
+ new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f);
+ new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f);
+ new_sp->time = interpf(sp->time, sp_next->time, 0.5f);
+ interp_v4_v4v4((float *)&new_sp->vertex_color,
+ (float *)&sp->vertex_color,
+ (float *)&sp_next->vertex_color,
+ 0.5f);
+ if (sp->dw && sp_next->dw) {
+ new_sp->totweight = MIN2(sp->totweight, sp_next->totweight);
+ new_sp->dw = MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, __func__);
+ for (uint32_t i = 0; i < new_sp->totweight; ++i) {
+ MDeformWeight *dw = &new_sp->dw[i];
+ MDeformWeight *dw_from = &sp->dw[i];
+ MDeformWeight *dw_to = &sp_next->dw[i];
+ dw->def_nr = dw_from->def_nr;
+ dw->weight = interpf(dw_from->weight, dw_to->weight, 0.5f);
+ }
+ }
+ BLI_insertlinkafter(&points, sp, new_sp);
+
+ tSampleEdge *se_prev = new_sample_edge_from_sample_points(sp, new_sp);
+ tSampleEdge *se_next = new_sample_edge_from_sample_points(new_sp, sp_next);
+ BLI_heap_insert(edges, -(se_prev->length_sq), se_prev);
+ BLI_heap_insert(edges, -(se_next->length_sq), se_next);
+
+ MEM_freeN(se);
+ num_points_needed--;
+ }
+
+ /* Edges are no longer needed. Heap is freed. */
+ BLI_heap_free(edges, (HeapFreeFP)MEM_freeN);
+
+ gps->totpoints = target_number;
+ gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
+ if (has_dverts) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
+ }
+
+ /* Convert list back to stroke point array. */
+ tSamplePoint *sp = points.first;
+ for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ copy_v3_v3(&pt->x, &sp->x);
+ pt->pressure = sp->pressure;
+ pt->strength = sp->strength;
+ pt->time = sp->time;
+ copy_v4_v4((float *)&pt->vert_color, (float *)&sp->vertex_color);
+
+ if (sp->dw) {
+ dvert->totweight = sp->totweight;
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__);
+ for (uint32_t j = 0; j < dvert->totweight; ++j) {
+ MDeformWeight *dw = &dvert->dw[j];
+ MDeformWeight *dw_from = &sp->dw[j];
+ dw->def_nr = dw_from->def_nr;
+ dw->weight = dw_from->weight;
+ }
+ }
+ if (select) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+
+ if (select) {
+ gps->flag |= GP_STROKE_SELECT;
+ }
+
+ /* Free the sample points. Important to use the mutable loop here because we are erasing the list
+ * elements. */
+ LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) {
+ if (temp->dw != NULL) {
+ MEM_freeN(temp->dw);
+ }
+ MEM_SAFE_FREE(temp);
+ }
+
+ /* Update the geometry of the stroke. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index ac81e4a5470..1be2cba31b5 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -534,7 +534,7 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format
* Check whether given modifier is not local (i.e. from linked data) when the object is a library
* override.
*
- * \param gmd May be NULL, in which case we consider it as a non-local modifier case.
+ * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
*/
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
const GpencilModifierData *gmd)
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.cc
index eec9013d067..fbf69357478 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -1,4 +1,4 @@
-/*
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -21,9 +21,10 @@
* \ingroup bke
*/
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
#include "CLG_log.h"
@@ -46,6 +47,7 @@
#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_global.h" /* only for G.background test */
#include "BKE_icons.h"
@@ -61,6 +63,8 @@
#include "BLO_read_write.h"
+#include "atomic_ops.h"
+
/**
* Only allow non-managed icons to be removed (by Python for eg).
* Previews & ID's have their own functions to remove icons.
@@ -73,28 +77,35 @@ enum {
static CLG_LogRef LOG = {"bke.icons"};
-static GHash *gIcons = NULL;
+/* Protected by gIconMutex. */
+static GHash *gIcons = nullptr;
+/* Protected by gIconMutex. */
static int gNextIconId = 1;
+/* Protected by gIconMutex. */
static int gFirstIconId = 1;
-static GHash *gCachedPreviews = NULL;
+std::mutex gIconMutex;
+
+/* Not mutex-protected! */
+static GHash *gCachedPreviews = nullptr;
/* Queue of icons for deferred deletion. */
typedef struct DeferredIconDeleteNode {
struct DeferredIconDeleteNode *next;
int icon_id;
} DeferredIconDeleteNode;
+/* Protected by gIconMutex. */
static LockfreeLinkList g_icon_delete_queue;
static void icon_free(void *val)
{
- Icon *icon = val;
+ Icon *icon = (Icon *)val;
if (icon) {
if (icon->obj_type == ICON_DATA_GEOM) {
- struct Icon_Geom *obj = icon->obj;
+ struct Icon_Geom *obj = (struct Icon_Geom *)icon->obj;
if (obj->mem) {
/* coords & colors are part of this memory. */
MEM_freeN((void *)obj->mem);
@@ -121,6 +132,12 @@ static void icon_free_data(int icon_id, Icon *icon)
if (icon->obj_type == ICON_DATA_ID) {
((ID *)(icon->obj))->icon_id = 0;
}
+ else if (icon->obj_type == ICON_DATA_IMBUF) {
+ ImBuf *imbuf = (ImBuf *)icon->obj;
+ if (imbuf) {
+ IMB_freeImBuf(imbuf);
+ }
+ }
else if (icon->obj_type == ICON_DATA_PREVIEW) {
((PreviewImage *)(icon->obj))->icon_id = 0;
}
@@ -131,8 +148,8 @@ static void icon_free_data(int icon_id, Icon *icon)
((struct Icon_Geom *)(icon->obj))->icon_id = 0;
}
else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
- StudioLight *sl = icon->obj;
- if (sl != NULL) {
+ StudioLight *sl = (StudioLight *)icon->obj;
+ if (sl != nullptr) {
BKE_studiolight_unset_icon_id(sl, icon_id);
}
}
@@ -141,19 +158,27 @@ static void icon_free_data(int icon_id, Icon *icon)
}
}
+static Icon *icon_ghash_lookup(int icon_id)
+{
+ std::scoped_lock lock(gIconMutex);
+ return (Icon *)BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+}
+
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
-static int get_next_free_id(void)
+static int get_next_free_id()
{
- BLI_assert(BLI_thread_is_main());
+ std::scoped_lock lock(gIconMutex);
int startId = gFirstIconId;
/* if we haven't used up the int number range, we just return the next int */
if (gNextIconId >= gFirstIconId) {
- return gNextIconId++;
+ int next_id = gNextIconId++;
+ return next_id;
}
- /* now we try to find the smallest icon id not stored in the gIcons hash */
+ /* Now we try to find the smallest icon id not stored in the gIcons hash.
+ * Don't use icon_ghash_lookup here, it would lock recursively (dead-lock). */
while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId) {
startId++;
}
@@ -189,13 +214,13 @@ void BKE_icons_free(void)
BLI_assert(BLI_thread_is_main());
if (gIcons) {
- BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
+ BLI_ghash_free(gIcons, nullptr, icon_free);
+ gIcons = nullptr;
}
if (gCachedPreviews) {
BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
- gCachedPreviews = NULL;
+ gCachedPreviews = nullptr;
}
BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
@@ -203,20 +228,21 @@ void BKE_icons_free(void)
void BKE_icons_deferred_free(void)
{
- BLI_assert(BLI_thread_is_main());
+ std::scoped_lock lock(gIconMutex);
for (DeferredIconDeleteNode *node =
(DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
- node != NULL;
+ node != nullptr;
node = node->next) {
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free);
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), nullptr, icon_free);
}
BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
}
static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
{
- PreviewImage *prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+ PreviewImage *prv_img = (PreviewImage *)MEM_mallocN(sizeof(PreviewImage) + deferred_data_size,
+ "img_prv");
memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
if (deferred_data_size) {
@@ -224,12 +250,26 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
}
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- prv_img->flag[i] |= PRV_CHANGED;
+ prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
+static PreviewImage *previewimg_deferred_create(const char *path, int source)
+{
+ /* We pack needed data for lazy loading (source type, in a single char, and path). */
+ const size_t deferred_data_size = strlen(path) + 2;
+ char *deferred_data;
+
+ PreviewImage *prv = previewimg_create_ex(deferred_data_size);
+ deferred_data = (char *)PRV_DEFERRED_DATA(prv);
+ deferred_data[0] = source;
+ memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+ return prv;
+}
+
PreviewImage *BKE_previewimg_create(void)
{
return previewimg_create_ex(0);
@@ -256,7 +296,7 @@ void BKE_previewimg_free(PreviewImage **prv)
{
if (prv && (*prv)) {
BKE_previewimg_freefunc(*prv);
- *prv = NULL;
+ *prv = nullptr;
}
}
@@ -267,7 +307,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
GPU_texture_free(prv->gputexture[size]);
}
prv->h[size] = prv->w[size] = 0;
- prv->flag[size] |= PRV_CHANGED;
+ prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
prv->flag[size] &= ~PRV_USER_EDITED;
prv->changed_timestamp[size] = 0;
}
@@ -275,21 +315,21 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
void BKE_previewimg_clear(struct PreviewImage *prv)
{
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- BKE_previewimg_clear_single(prv, i);
+ BKE_previewimg_clear_single(prv, (eIconSizes)i);
}
}
PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
{
- PreviewImage *prv_img = NULL;
+ PreviewImage *prv_img = nullptr;
if (prv) {
- prv_img = MEM_dupallocN(prv);
+ prv_img = (PreviewImage *)MEM_dupallocN(prv);
for (int i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
- prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
+ prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]);
}
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
}
}
return prv_img;
@@ -305,7 +345,7 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
if (old_prv_p && *old_prv_p) {
- BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
+ BLI_assert(new_prv_p != nullptr && ELEM(*new_prv_p, nullptr, *old_prv_p));
// const int new_icon_id = get_next_free_id();
// if (new_icon_id == 0) {
@@ -339,7 +379,13 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
break;
}
- return NULL;
+ return nullptr;
+}
+
+PreviewImage *BKE_previewimg_id_get(const ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ return prv_p ? *prv_p : nullptr;
}
void BKE_previewimg_id_free(ID *id)
@@ -355,18 +401,60 @@ PreviewImage *BKE_previewimg_id_ensure(ID *id)
PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
if (prv_p) {
- if (*prv_p == NULL) {
+ if (*prv_p == nullptr) {
*prv_p = BKE_previewimg_create();
}
return *prv_p;
}
- return NULL;
+ return nullptr;
+}
+
+void BKE_previewimg_id_custom_set(ID *id, const char *path)
+{
+ PreviewImage **prv = BKE_previewimg_id_get_p(id);
+
+ /* Thumbnail previews must use the deferred pipeline. But we force them to be immediately
+ * generated here still. */
+
+ if (*prv) {
+ BKE_previewimg_deferred_release(*prv);
+ }
+ *prv = previewimg_deferred_create(path, THB_SOURCE_IMAGE);
+
+ /* Can't lazy-render the preview on access. ID previews are saved to files and we want them to be
+ * there in time. Not only if something happened to have accessed it meanwhile. */
+ for (int i = 0; i < NUM_ICON_SIZES; i++) {
+ BKE_previewimg_ensure(*prv, i);
+ /* Prevent auto-updates. */
+ (*prv)->flag[i] |= PRV_USER_EDITED;
+ }
+}
+
+bool BKE_previewimg_id_supports_jobs(const ID *id)
+{
+ return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR);
+}
+
+void BKE_previewimg_deferred_release(PreviewImage *prv)
+{
+ if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
+ }
}
PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- return BLI_ghash_lookup(gCachedPreviews, name);
+ BLI_assert(BLI_thread_is_main());
+ return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name);
}
/**
@@ -374,14 +462,16 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
*/
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
- PreviewImage *prv = NULL;
+ BLI_assert(BLI_thread_is_main());
+
+ PreviewImage *prv = nullptr;
void **key_p, **prv_p;
if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
*key_p = BLI_strdup(name);
*prv_p = BKE_previewimg_create();
}
- prv = *prv_p;
+ prv = *(PreviewImage **)prv_p;
BLI_assert(prv);
return prv;
@@ -389,24 +479,27 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
/**
* Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
+ * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
*/
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
bool force_update)
{
- PreviewImage *prv = NULL;
+ BLI_assert(BLI_thread_is_main());
+
+ PreviewImage *prv = nullptr;
void **prv_p;
prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
if (prv_p) {
- prv = *prv_p;
+ prv = *(PreviewImage **)prv_p;
BLI_assert(prv);
}
if (prv && force_update) {
- const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
/* If same path, no need to re-allocate preview, just clear it up. */
BKE_previewimg_clear(prv);
@@ -417,15 +510,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
}
if (!prv) {
- /* We pack needed data for lazy loading (source type, in a single char, and path). */
- const size_t deferred_data_size = strlen(path) + 2;
- char *deferred_data;
-
- prv = previewimg_create_ex(deferred_data_size);
- deferred_data = PRV_DEFERRED_DATA(prv);
- deferred_data[0] = source;
- memcpy(&deferred_data[1], path, deferred_data_size - 1);
-
+ prv = previewimg_deferred_create(path, source);
force_update = true;
}
@@ -441,26 +526,13 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
return prv;
}
-void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
-{
- if (prv) {
- if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
- /* We cannot delete the preview while it is being loaded in another thread... */
- prv->tag |= PRV_TAG_DEFFERED_DELETE;
- return;
- }
- if (prv->icon_id) {
- BKE_icon_delete(prv->icon_id);
- }
- BKE_previewimg_freefunc(prv);
- }
-}
-
void BKE_previewimg_cached_release(const char *name)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+ BLI_assert(BLI_thread_is_main());
+
+ PreviewImage *prv = (PreviewImage *)BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
- BKE_previewimg_cached_release_pointer(prv);
+ BKE_previewimg_deferred_release(prv);
}
/**
@@ -475,12 +547,12 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
if (do_icon || do_preview) {
ImBuf *thumb;
- char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
int source = prv_deferred_data[0];
char *path = &prv_deferred_data[1];
int icon_w, icon_h;
- thumb = IMB_thumb_manage(path, THB_LARGE, source);
+ thumb = IMB_thumb_manage(path, THB_LARGE, (ThumbSource)source);
if (thumb) {
/* PreviewImage assumes premultiplied alhpa... */
@@ -489,8 +561,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
if (do_preview) {
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
- prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
}
if (do_icon) {
if (thumb->x > thumb->y) {
@@ -508,8 +580,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
IMB_scaleImBuf(thumb, icon_w, icon_h);
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
- prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
}
IMB_freeImBuf(thumb);
}
@@ -517,13 +589,45 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
+/**
+ * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
+ * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
+ */
+ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
+{
+ const unsigned int w = prv->w[size];
+ const unsigned int h = prv->h[size];
+ const unsigned int *rect = prv->rect[size];
+
+ ImBuf *ima = nullptr;
+
+ if (w > 0 && h > 0 && rect) {
+ /* first allocate imbuf for copying preview into it */
+ ima = IMB_allocImBuf(w, h, 32, IB_rect);
+ memcpy(ima->rect, rect, w * h * sizeof(*ima->rect));
+ }
+
+ return ima;
+}
+
+void BKE_previewimg_finish(PreviewImage *prv, const int size)
+{
+ /* Previews may be calculated on a thread. */
+ atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED);
+}
+
+bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
+{
+ return (prv->flag[size] & PRV_UNFINISHED) == 0;
+}
+
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
{
/* Note we write previews also for undo steps. It takes up some memory,
* but not doing so would causes all previews to be re-rendered after
* undo which is too expensive. */
- if (prv == NULL) {
+ if (prv == nullptr) {
return;
}
@@ -532,7 +636,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
if (!(U.flag & USER_SAVE_PREVIEWS)) {
prv_copy.w[1] = 0;
prv_copy.h[1] = 0;
- prv_copy.rect[1] = NULL;
+ prv_copy.rect[1] = nullptr;
}
BLO_write_struct_at_address(writer, PreviewImage, prv, &prv_copy);
if (prv_copy.rect[0]) {
@@ -545,7 +649,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
{
- if (prv == NULL) {
+ if (prv == nullptr) {
return;
}
@@ -553,7 +657,18 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
if (prv->rect[i]) {
BLO_read_data_address(reader, &prv->rect[i]);
}
- prv->gputexture[i] = NULL;
+ prv->gputexture[i] = nullptr;
+ /* For now consider previews read from file as finished to not confuse File Browser preview
+ * loading. That could be smarter and check if there's a preview job running instead.
+ * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag.
+ */
+ if ((prv->flag[i] & PRV_CHANGED) == 0) {
+ BKE_previewimg_finish(prv, i);
+ }
+ else {
+ /* Only for old files that didn't write the flag . */
+ prv->flag[i] |= PRV_UNFINISHED;
+ }
}
prv->icon_id = 0;
prv->tag = 0;
@@ -561,15 +676,13 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_icon_changed(const int icon_id)
{
- BLI_assert(BLI_thread_is_main());
-
- Icon *icon = NULL;
+ Icon *icon = nullptr;
if (!icon_id || G.background) {
return;
}
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = icon_ghash_lookup(icon_id);
if (icon) {
/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
@@ -584,7 +697,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- (*p_prv)->flag[i] |= PRV_CHANGED;
+ (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
(*p_prv)->changed_timestamp[i]++;
}
}
@@ -593,7 +706,7 @@ void BKE_icon_changed(const int icon_id)
static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
+ Icon *new_icon = (Icon *)MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj_type = obj_type;
new_icon->obj = obj;
@@ -601,10 +714,13 @@ static Icon *icon_create(int icon_id, int obj_type, void *obj)
new_icon->flag = 0;
/* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
+ new_icon->drawinfo = nullptr;
+ new_icon->drawinfo_free = nullptr;
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+ {
+ std::scoped_lock lock(gIconMutex);
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+ }
return new_icon;
}
@@ -731,17 +847,47 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
+/**
+ * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored
+ * separately.
+ * \note Transforms ownership of \a ibuf to the newly created icon.
+ */
+int BKE_icon_imbuf_create(ImBuf *ibuf)
+{
+ int icon_id = get_next_free_id();
+
+ Icon *icon = icon_create(icon_id, ICON_DATA_IMBUF, ibuf);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return icon_id;
+}
+
+ImBuf *BKE_icon_imbuf_get_buffer(int icon_id)
+{
+ Icon *icon = icon_ghash_lookup(icon_id);
+ if (!icon) {
+ CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
+ return nullptr;
+ }
+ if (icon->obj_type != ICON_DATA_IMBUF) {
+ CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id);
+ return nullptr;
+ }
+
+ return (ImBuf *)icon->obj;
+}
+
Icon *BKE_icon_get(const int icon_id)
{
BLI_assert(BLI_thread_is_main());
- Icon *icon = NULL;
+ Icon *icon = nullptr;
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = icon_ghash_lookup(icon_id);
if (!icon) {
CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
- return NULL;
+ return nullptr;
}
return icon;
@@ -749,10 +895,9 @@ Icon *BKE_icon_get(const int icon_id)
void BKE_icon_set(const int icon_id, struct Icon *icon)
{
- BLI_assert(BLI_thread_is_main());
-
void **val_p;
+ std::scoped_lock lock(gIconMutex);
if (BLI_ghash_ensure_p(gIcons, POINTER_FROM_INT(icon_id), &val_p)) {
CLOG_ERROR(&LOG, "icon already set: %d", icon_id);
return;
@@ -763,8 +908,10 @@ void BKE_icon_set(const int icon_id, struct Icon *icon)
static void icon_add_to_deferred_delete_queue(int icon_id)
{
- DeferredIconDeleteNode *node = MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
+ DeferredIconDeleteNode *node = (DeferredIconDeleteNode *)MEM_mallocN(
+ sizeof(DeferredIconDeleteNode), __func__);
node->icon_id = icon_id;
+ /* Doesn't need lock. */
BLI_linklist_lockfree_insert(&g_icon_delete_queue, (LockfreeLinkNode *)node);
}
@@ -782,7 +929,8 @@ void BKE_icon_id_delete(struct ID *id)
}
BKE_icons_deferred_free();
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free);
+ std::scoped_lock lock(gIconMutex);
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free);
}
/**
@@ -795,8 +943,8 @@ bool BKE_icon_delete(const int icon_id)
return false;
}
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
- if (icon) {
+ std::scoped_lock lock(gIconMutex);
+ if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr)) {
icon_free_data(icon_id, icon);
icon_free(icon);
return true;
@@ -812,7 +960,9 @@ bool BKE_icon_delete_unmanaged(const int icon_id)
return false;
}
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ std::scoped_lock lock(gIconMutex);
+
+ Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr);
if (icon) {
if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
@@ -847,52 +997,52 @@ int BKE_icon_geom_ensure(struct Icon_Geom *geom)
return geom->icon_id;
}
-struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
+struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len)
{
BLI_assert(BLI_thread_is_main());
if (data_len <= 8) {
- goto fail;
+ return nullptr;
}
+ /* Wrapper for RAII early exit cleanups. */
+ std::unique_ptr<uchar> data_wrapper(std::move(data));
+
/* Skip the header. */
data_len -= 8;
const int div = 3 * 2 * 3;
const int coords_len = data_len / div;
if (coords_len * div != data_len) {
- goto fail;
+ return nullptr;
}
const uchar header[4] = {'V', 'C', 'O', 0};
- const uchar *p = data;
+ uchar *p = data_wrapper.get();
if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
- goto fail;
+ return nullptr;
}
p += 4;
- struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ struct Icon_Geom *geom = (struct Icon_Geom *)MEM_mallocN(sizeof(*geom), __func__);
geom->coords_range[0] = (int)*p++;
geom->coords_range[1] = (int)*p++;
/* x, y ignored for now */
p += 2;
geom->coords_len = coords_len;
- geom->coords = (void *)p;
- geom->colors = (void *)(p + (data_len / 3));
+ geom->coords = reinterpret_cast<decltype(geom->coords)>(p);
+ geom->colors = reinterpret_cast<decltype(geom->colors)>(p + (data_len / 3));
geom->icon_id = 0;
- geom->mem = data;
+ /* Move buffer ownership to C buffer. */
+ geom->mem = data_wrapper.release();
return geom;
-
-fail:
- MEM_freeN((void *)data);
- return NULL;
}
struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
{
BLI_assert(BLI_thread_is_main());
size_t data_len;
- uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
- if (data == NULL) {
- return NULL;
+ uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ if (data == nullptr) {
+ return nullptr;
}
return BKE_icon_geom_from_memory(data, data_len);
}
diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index f8a1113f69b..433f0e97844 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -26,6 +26,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "DNA_ID.h"
+
#include "BKE_idprop.h"
#include "BKE_idtype.h"
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index 44bf8f0e4db..1889d1c4eb0 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -36,6 +36,7 @@
#include "BLT_translation.h"
#include "DNA_ID.h"
+#include "DNA_collection_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index cd2ed32cd4f..228aed265cf 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -54,6 +54,7 @@
#include "DNA_camera_types.h"
#include "DNA_defaults.h"
#include "DNA_light_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -225,14 +226,21 @@ static void image_foreach_cache(ID *id,
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Image *ima = (Image *)id;
- if (ima->id.us > 0 || BLO_write_is_undo(writer)) {
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (ima->id.us > 0 || is_undo) {
ImagePackedFile *imapf;
- /* Some trickery to keep forward compatibility of packed images. */
BLI_assert(ima->packedfile == NULL);
- if (ima->packedfiles.first != NULL) {
- imapf = ima->packedfiles.first;
- ima->packedfile = imapf->packedfile;
+ /* Do not store packed files in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) {
+ BLI_listbase_clear(&ima->packedfiles);
+ }
+ else {
+ /* Some trickery to keep forward compatibility of packed images. */
+ if (ima->packedfiles.first != NULL) {
+ imapf = ima->packedfiles.first;
+ ima->packedfile = imapf->packedfile;
+ }
}
/* write LibData */
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
index 9ed233ab34c..50138b34fa3 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -62,7 +62,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
return ibuf->rect_float != NULL;
}
}
- else if (ibuf) {
+ if (ibuf) {
if (ibuf->rect_float) {
return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 6a852df95c6..0e611b21304 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -467,7 +467,9 @@ static char *shapekey_adrcodes_to_paths(ID *id, int adrcode, int *UNUSED(array_i
/* setting that we alter is the "value" (i.e. keyblock.curval) */
if (kb) {
/* Use the keyblock name, escaped, so that path lookups for this will work */
- BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb->name);
+ char kb_name_esc[sizeof(kb->name) * 2];
+ BLI_str_escape(kb_name_esc, kb->name, sizeof(kb_name_esc));
+ BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb_name_esc);
}
else {
/* Fallback - Use the adrcode as index directly, so that this can be manually fixed */
@@ -1118,7 +1120,7 @@ static char *get_rna_access(ID *id,
propname = "speed_fader";
break;
case SEQ_FAC_OPACITY:
- propname = "blend_opacity";
+ propname = "blend_alpha";
break;
}
/* XXX this doesn't seem to be included anywhere in sequencer RNA... */
@@ -1160,7 +1162,12 @@ static char *get_rna_access(ID *id,
/* note, strings are not escapted and they should be! */
if ((actname && actname[0]) && (constname && constname[0])) {
/* Constraint in Pose-Channel */
- BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname, constname);
+ char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
+ char constname_esc[sizeof(((bConstraint *)NULL)->name) * 2];
+ BLI_str_escape(actname_esc, actname, sizeof(actname_esc));
+ BLI_str_escape(constname_esc, constname, sizeof(constname_esc));
+ BLI_snprintf(
+ buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname_esc, constname_esc);
}
else if (actname && actname[0]) {
if ((blocktype == ID_OB) && STREQ(actname, "Object")) {
@@ -1174,16 +1181,22 @@ static char *get_rna_access(ID *id,
}
else {
/* Pose-Channel */
- BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname);
+ char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
+ BLI_str_escape(actname_esc, actname, sizeof(actname_esc));
+ BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname_esc);
}
}
else if (constname && constname[0]) {
/* Constraint in Object */
- BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname);
+ char constname_esc[sizeof(((bConstraint *)NULL)->name) * 2];
+ BLI_str_escape(constname_esc, constname, sizeof(constname_esc));
+ BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname_esc);
}
else if (seq) {
/* Sequence names in Scene */
- BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq->name + 2);
+ char seq_name_esc[(sizeof(seq->name) - 2) * 2];
+ BLI_str_escape(seq_name_esc, seq->name + 2, sizeof(seq_name_esc));
+ BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq_name_esc);
}
else {
buf[0] = '\0'; /* empty string */
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 7468112b40e..433d64a5927 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -108,7 +108,8 @@ static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data)
static void shapekey_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Key *key = (Key *)id;
- if (key->id.us > 0 || BLO_write_is_undo(writer)) {
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (key->id.us > 0 || is_undo) {
/* write LibData */
BLO_write_id_struct(writer, Key, id_address, &key->id);
BKE_id_blend_write(writer, &key->id);
@@ -119,9 +120,15 @@ static void shapekey_blend_write(BlendWriter *writer, ID *id, const void *id_add
/* direct data */
LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
- BLO_write_struct(writer, KeyBlock, kb);
- if (kb->data) {
- BLO_write_raw(writer, kb->totelem * key->elemsize, kb->data);
+ KeyBlock tmp_kb = *kb;
+ /* Do not store actual geometry data in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(key) && !is_undo) {
+ tmp_kb.totelem = 0;
+ tmp_kb.data = NULL;
+ }
+ BLO_write_struct_at_address(writer, KeyBlock, kb, &tmp_kb);
+ if (tmp_kb.data != NULL) {
+ BLO_write_raw(writer, tmp_kb.totelem * key->elemsize, tmp_kb.data);
}
}
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 8a699e31f37..fbad0d920ed 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -2054,7 +2054,7 @@ static void bke_view_layer_verify_aov_cb(void *userdata,
const char *name,
int UNUSED(channels),
const char *UNUSED(chanid),
- int UNUSED(type))
+ eNodeSocketDatatype UNUSED(type))
{
GHash *name_count = userdata;
void **value_p;
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 21a77e2b45a..be7ce34f7e6 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -37,6 +37,7 @@
/* all types are needed here, in order to do memory operations */
#include "DNA_ID.h"
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_node_types.h"
@@ -55,6 +56,7 @@
#include "BKE_anim_data.h"
#include "BKE_armature.h"
+#include "BKE_asset.h"
#include "BKE_bpath.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -2264,6 +2266,12 @@ bool BKE_id_is_in_global_main(ID *id)
return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
}
+bool BKE_id_can_be_asset(const ID *id)
+{
+ return !ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY(id) &&
+ BKE_idtype_idcode_is_linkable(GS(id->name));
+}
+
/************************* Datablock order in UI **************************/
static int *id_order_get(ID *id)
@@ -2361,6 +2369,10 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
void BKE_id_blend_write(BlendWriter *writer, ID *id)
{
+ if (id->asset_data) {
+ BKE_asset_metadata_write(writer, id->asset_data);
+ }
+
/* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
IDP_BlendWrite(writer, id->properties);
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 1e45a3c1163..7199bd0f13c 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -31,6 +31,7 @@
#include "BLI_listbase.h"
#include "BKE_anim_data.h"
+#include "BKE_asset.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -64,6 +65,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
id->override_library = NULL;
}
+ if (id->asset_data) {
+ BKE_asset_metadata_free(&id->asset_data);
+ }
+
BKE_animdata_free(id, do_id_user);
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index d82315a0e7f..cabc80d4024 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -369,6 +369,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
static bool lib_override_hierarchy_recursive_tag(Main *bmain,
ID *id,
const uint tag,
+ const uint missing_tag,
Library *override_group_lib_reference)
{
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
@@ -377,9 +378,16 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
return (id->tag & tag) != 0;
}
+ /* Note: in case some reference ID is missing from linked data (and therefore its override uses
+ * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */
if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
id->override_library->reference->lib == override_group_lib_reference) {
- id->tag |= tag;
+ if (id->override_library->reference->tag & LIB_TAG_MISSING) {
+ id->tag |= missing_tag;
+ }
+ else {
+ id->tag |= tag;
+ }
}
/* This way we won't process again that ID, should we encounter it again through another
@@ -397,7 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
/* We only consider IDs from the same library. */
if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
if (lib_override_hierarchy_recursive_tag(
- bmain, *entry->id_pointer, tag, override_group_lib_reference) &&
+ bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
override_group_lib_reference == NULL) {
id->tag |= tag;
}
@@ -430,7 +438,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
/* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key
* has a driver using an armature object's bone, we need to override the shape-key/obdata,
* the objects using them, etc.) */
- lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL);
+ lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL);
BKE_main_relations_free(bmain);
}
@@ -447,6 +455,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
void BKE_lib_override_library_override_group_tag(Main *bmain,
ID *id_root,
const uint tag,
+ const uint missing_tag,
const bool do_create_main_relashionships)
{
if (do_create_main_relashionships) {
@@ -456,7 +465,7 @@ void BKE_lib_override_library_override_group_tag(Main *bmain,
/* We tag all liboverride data-blocks from the same library as reference one,
* being used by the root ID. */
lib_override_hierarchy_recursive_tag(
- bmain, id_root, tag, id_root->override_library->reference->lib);
+ bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib);
BKE_main_relations_free(bmain);
}
@@ -492,8 +501,9 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da
}
/* We tag all collections and objects for override. And we also tag all other data-blocks which
- * would use one of those. */
- if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ * would use one of those.
+ * Note: missing IDs (aka placeholders) are never overridden. */
+ if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -692,6 +702,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
&ob_proxy->proxy->id;
ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
+ /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
+ * sure this is a valid state, but for now just abort the overriding process. */
+ if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
+ return false;
+ }
+
/* We manually convert the proxy object into a library override, further override handling will
* then be handled by `BKE_lib_override_library_create()` just as for a regular override
* creation.
@@ -725,7 +741,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
/* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
* linked reference ones to be overridden again. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
+ BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
GHash *linkedref_to_old_override = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
@@ -835,6 +851,12 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
id->tag &= ~LIB_TAG_DOIT;
}
+ /* Also cleanup old overrides that went missing in new linked data. */
+ else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) {
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY(id));
+ id->tag |= LIB_TAG_DOIT;
+ id->tag &= ~LIB_TAG_MISSING;
+ }
}
FOREACH_MAIN_ID_END;
BKE_id_multi_tagged_delete(bmain);
@@ -876,7 +898,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
id_root->tag |= LIB_TAG_DOIT;
/* Tag all library overrides in the chains of dependencies from the given root one. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
+ BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 9e3189afee9..56f7bb0be6f 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -24,6 +24,7 @@
#include "BLI_utildefines.h"
+#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "BKE_armature.h"
@@ -342,7 +343,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, (bNodeTree *)new_id);
+ ntreeUpdateAllUsers(bmain, new_id);
}
/**
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 9ccdf5189d1..53f2a85fdad 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -173,24 +173,53 @@ static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Mesh *mesh = (Mesh *)id;
- if (mesh->id.us > 0 || BLO_write_is_undo(writer)) {
- /* cache only - don't write */
- mesh->mface = NULL;
- mesh->totface = 0;
- memset(&mesh->fdata, 0, sizeof(mesh->fdata));
- memset(&mesh->runtime, 0, sizeof(mesh->runtime));
-
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (mesh->id.us > 0 || is_undo) {
CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ /* cache only - don't write */
+ mesh->mface = NULL;
+ mesh->totface = 0;
+ memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
flayers = flayers_buff;
- CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
- CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+
+ /* Do not store actual geometry data in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
+ mesh->mvert = NULL;
+ mesh->totvert = 0;
+ memset(&mesh->vdata, 0, sizeof(mesh->vdata));
+ vlayers = vlayers_buff;
+
+ mesh->medge = NULL;
+ mesh->totedge = 0;
+ memset(&mesh->edata, 0, sizeof(mesh->edata));
+ elayers = elayers_buff;
+
+ mesh->mloop = NULL;
+ mesh->totloop = 0;
+ memset(&mesh->ldata, 0, sizeof(mesh->ldata));
+ llayers = llayers_buff;
+
+ mesh->mpoly = NULL;
+ mesh->totpoly = 0;
+ memset(&mesh->pdata, 0, sizeof(mesh->pdata));
+ players = players_buff;
+ }
+ else {
+ CustomData_blend_write_prepare(
+ &mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_blend_write_prepare(
+ &mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ CustomData_blend_write_prepare(
+ &mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
+ CustomData_blend_write_prepare(
+ &mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ }
BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
BKE_id_blend_write(writer, &mesh->id);
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 8272bd07411..73883afe19e 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1460,7 +1460,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
return result;
}
-/* This is a Mesh-based copy of the same function in DerivedMesh.c */
+/* This is a Mesh-based copy of the same function in DerivedMesh.cc */
static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
new file mode 100644
index 00000000000..527288d06cf
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -0,0 +1,505 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing":
+ * https://github.com/fedackb/mesh-fairing.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_map.hh"
+#include "BLI_math.h"
+#include "BLI_vector.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "MEM_guardedalloc.h"
+#include "eigen_capi.h"
+
+using blender::Map;
+using blender::Vector;
+using std::array;
+
+class VertexWeight {
+ public:
+ virtual float weight_at_index(const int index) = 0;
+ virtual ~VertexWeight() = default;
+};
+
+class LoopWeight {
+ public:
+ virtual float weight_at_index(const int index) = 0;
+ virtual ~LoopWeight() = default;
+};
+
+class FairingContext {
+ public:
+ /* Get coordinates of vertices which are adjacent to the loop with specified index. */
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) = 0;
+
+ /* Get the other vertex index for a loop. */
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) = 0;
+
+ int vertex_count_get()
+ {
+ return totvert_;
+ }
+
+ int loop_count_get()
+ {
+ return totvert_;
+ }
+
+ MeshElemMap *vertex_loop_map_get(const int v)
+ {
+ return &vlmap_[v];
+ }
+
+ float *vertex_deformation_co_get(const int v)
+ {
+ return co_[v];
+ }
+
+ virtual ~FairingContext() = default;
+
+ void fair_vertices(bool *affected,
+ const eMeshFairingDepth depth,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+
+ fair_vertices_ex(affected, (int)depth, vertex_weight, loop_weight);
+ }
+
+ protected:
+ Vector<float *> co_;
+
+ int totvert_;
+ int totloop_;
+
+ MeshElemMap *vlmap_;
+ int *vlmap_mem_;
+
+ private:
+ void fair_setup_fairing(const int v,
+ const int i,
+ LinearSolver *solver,
+ float multiplier,
+ const int depth,
+ Map<int, int> &vert_col_map,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+ if (depth == 0) {
+ if (vert_col_map.contains(v)) {
+ const int j = vert_col_map.lookup(v);
+ EIG_linear_solver_matrix_add(solver, i, j, -multiplier);
+ return;
+ }
+ for (int j = 0; j < 3; j++) {
+ EIG_linear_solver_right_hand_side_add(solver, j, i, multiplier * co_[v][j]);
+ }
+ return;
+ }
+
+ float w_ij_sum = 0;
+ const float w_i = vertex_weight->weight_at_index(v);
+ MeshElemMap *vlmap_elem = &vlmap_[v];
+ for (int l = 0; l < vlmap_elem->count; l++) {
+ const int l_index = vlmap_elem->indices[l];
+ const int other_vert = other_vertex_index_from_loop(l_index, v);
+ const float w_ij = loop_weight->weight_at_index(l_index);
+ w_ij_sum += w_ij;
+ fair_setup_fairing(other_vert,
+ i,
+ solver,
+ w_i * w_ij * multiplier,
+ depth - 1,
+ vert_col_map,
+ vertex_weight,
+ loop_weight);
+ }
+ fair_setup_fairing(v,
+ i,
+ solver,
+ -1 * w_i * w_ij_sum * multiplier,
+ depth - 1,
+ vert_col_map,
+ vertex_weight,
+ loop_weight);
+ }
+
+ void fair_vertices_ex(bool *affected,
+ const int order,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+ Map<int, int> vert_col_map;
+ int num_affected_vertices = 0;
+ for (int i = 0; i < totvert_; i++) {
+ if (!affected[i]) {
+ continue;
+ }
+ vert_col_map.add(i, num_affected_vertices);
+ num_affected_vertices++;
+ }
+
+ /* Early return, nothing to do. */
+ if (num_affected_vertices == 0 || num_affected_vertices == totvert_) {
+ return;
+ }
+
+ /* Setup fairing matrices */
+ LinearSolver *solver = EIG_linear_solver_new(num_affected_vertices, num_affected_vertices, 3);
+ for (auto item : vert_col_map.items()) {
+ const int v = item.key;
+ const int col = item.value;
+ fair_setup_fairing(v, col, solver, 1.0f, order, vert_col_map, vertex_weight, loop_weight);
+ }
+
+ /* Solve linear system */
+ EIG_linear_solver_solve(solver);
+
+ /* Copy the result back to the mesh */
+ for (auto item : vert_col_map.items()) {
+ const int v = item.key;
+ const int col = item.value;
+ for (int j = 0; j < 3; j++) {
+ co_[v][j] = EIG_linear_solver_variable_get(solver, j, col);
+ }
+ }
+
+ /* Free solver data */
+ EIG_linear_solver_delete(solver);
+ }
+};
+
+class MeshFairingContext : public FairingContext {
+ public:
+ MeshFairingContext(Mesh *mesh, MVert *deform_mverts)
+ {
+ totvert_ = mesh->totvert;
+ totloop_ = mesh->totloop;
+
+ medge_ = mesh->medge;
+ mpoly_ = mesh->mpoly;
+ mloop_ = mesh->mloop;
+ BKE_mesh_vert_loop_map_create(&vlmap_,
+ &vlmap_mem_,
+ mesh->mpoly,
+ mesh->mloop,
+ mesh->totvert,
+ mesh->totpoly,
+ mesh->totloop);
+
+ /* Deformation coords. */
+ co_.reserve(mesh->totvert);
+ if (deform_mverts) {
+ for (int i = 0; i < mesh->totvert; i++) {
+ co_[i] = deform_mverts[i].co;
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++) {
+ co_[i] = mesh->mvert[i].co;
+ }
+ }
+
+ loop_to_poly_map_.reserve(mesh->totloop);
+ for (int i = 0; i < mesh->totpoly; i++) {
+ for (int l = 0; l < mesh->mpoly[i].totloop; l++) {
+ loop_to_poly_map_[l + mesh->mpoly[i].loopstart] = i;
+ }
+ }
+ }
+
+ ~MeshFairingContext()
+ {
+ MEM_SAFE_FREE(vlmap_);
+ MEM_SAFE_FREE(vlmap_mem_);
+ }
+
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) override
+ {
+ const int vert = mloop_[loop].v;
+ const MPoly *p = &mpoly_[loop_to_poly_map_[loop]];
+ const int corner = poly_find_loop_from_vert(p, &mloop_[p->loopstart], vert);
+ copy_v3_v3(r_adj_next, co_[ME_POLY_LOOP_NEXT(mloop_, p, corner)->v]);
+ copy_v3_v3(r_adj_prev, co_[ME_POLY_LOOP_PREV(mloop_, p, corner)->v]);
+ }
+
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ {
+ MEdge *e = &medge_[mloop_[loop].e];
+ if (e->v1 == v) {
+ return e->v2;
+ }
+ return e->v1;
+ }
+
+ protected:
+ Mesh *mesh_;
+ MLoop *mloop_;
+ MPoly *mpoly_;
+ MEdge *medge_;
+ Vector<int> loop_to_poly_map_;
+};
+
+class BMeshFairingContext : public FairingContext {
+ public:
+ BMeshFairingContext(BMesh *bm)
+ {
+ this->bm = bm;
+ totvert_ = bm->totvert;
+ totloop_ = bm->totloop;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ /* Deformation coords. */
+ co_.reserve(bm->totvert);
+ for (int i = 0; i < bm->totvert; i++) {
+ BMVert *v = BM_vert_at_index(bm, i);
+ co_[i] = v->co;
+ }
+
+ bmloop_.reserve(bm->totloop);
+ vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(sizeof(MeshElemMap), bm->totvert, "bmesh loop map");
+ vlmap_mem_ = (int *)MEM_malloc_arrayN(sizeof(int), bm->totloop, "bmesh loop map mempool");
+
+ BMVert *v;
+ BMLoop *l;
+ BMIter iter;
+ BMIter loop_iter;
+ int index_iter = 0;
+
+ /* This initializes both the bmloop and the vlmap for bmesh in a single loop. */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ int loop_count = 0;
+ const int vert_index = BM_elem_index_get(v);
+ vlmap_[vert_index].indices = &vlmap_mem_[index_iter];
+ BM_ITER_ELEM (l, &loop_iter, v, BM_LOOPS_OF_VERT) {
+ const int loop_index = BM_elem_index_get(l);
+ bmloop_[loop_index] = l;
+ vlmap_mem_[index_iter] = loop_index;
+ index_iter++;
+ loop_count++;
+ }
+ vlmap_[vert_index].count = loop_count;
+ }
+ }
+
+ ~BMeshFairingContext()
+ {
+ MEM_SAFE_FREE(vlmap_);
+ MEM_SAFE_FREE(vlmap_mem_);
+ }
+
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) override
+ {
+ copy_v3_v3(r_adj_next, bmloop_[loop]->next->v->co);
+ copy_v3_v3(r_adj_prev, bmloop_[loop]->prev->v->co);
+ }
+
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ {
+ BMLoop *l = bmloop_[loop];
+ BMVert *bmvert = BM_vert_at_index(bm, v);
+ BMVert *bm_other_vert = BM_edge_other_vert(l->e, bmvert);
+ return BM_elem_index_get(bm_other_vert);
+ }
+
+ protected:
+ BMesh *bm;
+ Vector<BMLoop *> bmloop_;
+};
+
+class UniformVertexWeight : public VertexWeight {
+ public:
+ UniformVertexWeight(FairingContext *fairing_context)
+ {
+ const int totvert = fairing_context->vertex_count_get();
+ vertex_weights_.reserve(totvert);
+ for (int i = 0; i < totvert; i++) {
+ const int tot_loop = fairing_context->vertex_loop_map_get(i)->count;
+ if (tot_loop != 0) {
+ vertex_weights_[i] = 1.0f / tot_loop;
+ }
+ else {
+ vertex_weights_[i] = FLT_MAX;
+ }
+ }
+ }
+ ~UniformVertexWeight() = default;
+
+ float weight_at_index(const int index) override
+ {
+ return vertex_weights_[index];
+ }
+
+ private:
+ Vector<float> vertex_weights_;
+};
+
+class VoronoiVertexWeight : public VertexWeight {
+
+ public:
+ VoronoiVertexWeight(FairingContext *fairing_context)
+ {
+
+ const int totvert = fairing_context->vertex_count_get();
+ vertex_weights_.reserve(totvert);
+ for (int i = 0; i < totvert; i++) {
+
+ float area = 0.0f;
+ float a[3];
+ copy_v3_v3(a, fairing_context->vertex_deformation_co_get(i));
+ const float acute_threshold = M_PI_2;
+
+ MeshElemMap *vlmap_elem = fairing_context->vertex_loop_map_get(i);
+ for (int l = 0; l < vlmap_elem->count; l++) {
+ const int l_index = vlmap_elem->indices[l];
+
+ float b[3], c[3], d[3];
+ fairing_context->adjacents_coords_from_loop(l_index, b, c);
+
+ if (angle_v3v3v3(c, fairing_context->vertex_deformation_co_get(i), b) < acute_threshold) {
+ calc_circumcenter(d, a, b, c);
+ }
+ else {
+ add_v3_v3v3(d, b, c);
+ mul_v3_fl(d, 0.5f);
+ }
+
+ float t[3];
+ add_v3_v3v3(t, a, b);
+ mul_v3_fl(t, 0.5f);
+ area += area_tri_v3(a, t, d);
+
+ add_v3_v3v3(t, a, c);
+ mul_v3_fl(t, 0.5f);
+ area += area_tri_v3(a, d, t);
+ }
+
+ vertex_weights_[i] = area != 0.0f ? 1.0f / area : 1e12;
+ }
+ }
+ ~VoronoiVertexWeight() = default;
+
+ float weight_at_index(const int index) override
+ {
+ return vertex_weights_[index];
+ }
+
+ private:
+ Vector<float> vertex_weights_;
+
+ void calc_circumcenter(float r[3], const float a[3], const float b[3], const float c[3])
+ {
+ float ab[3];
+ sub_v3_v3v3(ab, b, a);
+
+ float ac[3];
+ sub_v3_v3v3(ac, c, a);
+
+ float ab_cross_ac[3];
+ cross_v3_v3v3(ab_cross_ac, ab, ac);
+
+ if (len_squared_v3(ab_cross_ac) > 0.0f) {
+ float d[3];
+ cross_v3_v3v3(d, ab_cross_ac, ab);
+ mul_v3_fl(d, len_squared_v3(ac));
+
+ float t[3];
+ cross_v3_v3v3(t, ac, ab_cross_ac);
+ mul_v3_fl(t, len_squared_v3(ab));
+
+ add_v3_v3(d, t);
+
+ mul_v3_fl(d, 1.0f / (2.0f * len_squared_v3(ab_cross_ac)));
+
+ add_v3_v3v3(r, a, d);
+ return;
+ }
+ copy_v3_v3(r, a);
+ }
+};
+
+class UniformLoopWeight : public LoopWeight {
+ public:
+ float weight_at_index(const int UNUSED(index)) override
+ {
+ return 1.0f;
+ }
+};
+
+static void prefair_and_fair_vertices(FairingContext *fairing_context,
+ bool *affected_vertices,
+ const eMeshFairingDepth depth)
+{
+ /* Prefair. */
+ UniformVertexWeight *uniform_vertex_weights = new UniformVertexWeight(fairing_context);
+ UniformLoopWeight *uniform_loop_weights = new UniformLoopWeight();
+ fairing_context->fair_vertices(
+ affected_vertices, depth, uniform_vertex_weights, uniform_loop_weights);
+ delete uniform_vertex_weights;
+
+ /* Fair. */
+ VoronoiVertexWeight *voronoi_vertex_weights = new VoronoiVertexWeight(fairing_context);
+ /* TODO: Implemente cotangent loop weights. */
+ fairing_context->fair_vertices(
+ affected_vertices, depth, voronoi_vertex_weights, uniform_loop_weights);
+
+ delete uniform_loop_weights;
+ delete voronoi_vertex_weights;
+}
+
+void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh,
+ struct MVert *deform_mverts,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth)
+{
+ MeshFairingContext *fairing_context = new MeshFairingContext(mesh, deform_mverts);
+ prefair_and_fair_vertices(fairing_context, affect_vertices, depth);
+ delete fairing_context;
+}
+
+void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth)
+{
+ BMeshFairingContext *fairing_context = new BMeshFairingContext(bm);
+ prefair_and_fair_vertices(fairing_context, affect_vertices, depth);
+ delete fairing_context;
+}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 3496e05c6e5..ba0f59f6363 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
+#include "DNA_dynamicpaint_types.h"
#include "DNA_fluid_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_mesh_types.h"
@@ -578,7 +579,7 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re
* Check whether given modifier is not local (i.e. from linked data) when the object is a library
* override.
*
- * \param md May be NULL, in which case we consider it as a non-local modifier case.
+ * \param md: May be NULL, in which case we consider it as a non-local modifier case.
*/
bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md)
{
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h
index 39c6da0b6c8..0a03387282f 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.h
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.h
@@ -26,10 +26,8 @@
#include "BLI_sys_types.h"
struct BMesh;
-struct Depsgraph;
struct Mesh;
struct MultiresModifierData;
-struct Object;
typedef struct MultiresUnsubdivideGrid {
/* For sanity checks. */
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index ebd9317fcf1..75230f9045c 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -334,11 +334,8 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
/* generic settings
* - selected flag to highlight this to the user
* - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects
- * - (XXX) synchronization of strip-length in accordance with changes to action-length
- * is not done though, since this should only really happens in editmode for strips now
- * though this decision is still subject to further review...
*/
- strip->flag = NLASTRIP_FLAG_SELECT;
+ strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH;
/* assign the action reference */
strip->act = act;
@@ -1195,7 +1192,7 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
* Check whether given NLA track is not local (i.e. from linked data) when the object is a library
* override.
*
- * \param nlt May be NULL, in which case we consider it as a non-local track case.
+ * \param nlt: May be NULL, in which case we consider it as a non-local track case.
*/
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
{
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 31de95817fd..415eb14be66 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -35,6 +35,7 @@
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
@@ -59,6 +60,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_colortools.h"
+#include "BKE_cryptomatte.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
@@ -274,6 +276,11 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
break;
}
+ case SOCK_COLLECTION: {
+ bNodeSocketValueCollection *default_value = sock->default_value;
+ BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ break;
+ }
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@@ -373,6 +380,9 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case SOCK_IMAGE:
BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value);
break;
+ case SOCK_COLLECTION:
+ BLO_write_struct(writer, bNodeSocketValueCollection, sock->default_value);
+ break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
@@ -482,10 +492,18 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
+ /* Update the matte_id so the files can be opened in versions that don't
+ * use `CryptomatteEntry`. */
+ MEM_SAFE_FREE(nc->matte_id);
+ nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc);
if (nc->matte_id) {
BLO_write_string(writer, nc->matte_id);
}
+ LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
+ BLO_write_struct(writer, CryptomatteEntry, entry);
+ }
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
+ MEM_SAFE_FREE(nc->matte_id);
}
else if (node->typeinfo != &NodeTypeUndefined) {
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
@@ -637,6 +655,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
+ BLO_read_list(reader, &nc->entries);
break;
}
case TEX_NODE_IMAGE: {
@@ -709,6 +728,11 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
+ case SOCK_COLLECTION: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ BLO_read_id_address(reader, lib, &default_value->value);
+ break;
+ }
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@@ -788,6 +812,11 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
BLO_expand(expander, default_value->value);
break;
}
+ case SOCK_COLLECTION: {
+ bNodeSocketValueCollection *default_value = sock->default_value;
+ BLO_expand(expander, default_value->value);
+ break;
+ }
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@@ -1345,6 +1374,11 @@ static void socket_id_user_increment(bNodeSocket *sock)
id_us_plus((ID *)default_value->value);
break;
}
+ case SOCK_COLLECTION: {
+ bNodeSocketValueCollection *default_value = sock->default_value;
+ id_us_plus((ID *)default_value->value);
+ break;
+ }
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@@ -1372,6 +1406,11 @@ static void socket_id_user_decrement(bNodeSocket *sock)
id_us_min(&default_value->value->id);
break;
}
+ case SOCK_COLLECTION: {
+ bNodeSocketValueCollection *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@@ -1511,6 +1550,8 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketImage";
case SOCK_GEOMETRY:
return "NodeSocketGeometry";
+ case SOCK_COLLECTION:
+ return "NodeSocketCollection";
}
return NULL;
}
@@ -1578,6 +1619,8 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceImage";
case SOCK_GEOMETRY:
return "NodeSocketInterfaceGeometry";
+ case SOCK_COLLECTION:
+ return "NodeSocketInterfaceCollection";
}
return NULL;
}
@@ -3960,9 +4003,9 @@ void ntreeUpdateAllNew(Main *main)
FOREACH_NODETREE_END;
}
-void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup)
+void ntreeUpdateAllUsers(Main *main, ID *id)
{
- if (ngroup == NULL) {
+ if (id == NULL) {
return;
}
@@ -3971,7 +4014,7 @@ void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup)
bool need_update = false;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == &ngroup->id) {
+ if (node->id == id) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
}
@@ -3986,13 +4029,16 @@ void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup)
}
FOREACH_NODETREE_END;
- if (ngroup->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (Object *, object, &main->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == ngroup) {
- MOD_nodes_update_interface(object, nmd);
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *ngroup = (bNodeTree *)id;
+ if (ngroup->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (Object *, object, &main->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == ngroup) {
+ MOD_nodes_update_interface(object, nmd);
+ }
}
}
}
@@ -4041,7 +4087,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
}
if (bmain) {
- ntreeUpdateAllUsers(bmain, ntree);
+ ntreeUpdateAllUsers(bmain, &ntree->id);
}
if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
@@ -4682,6 +4728,7 @@ static void registerGeometryNodes(void)
{
register_node_type_geo_group();
+ register_node_type_geo_attribute_fill();
register_node_type_geo_triangulate();
register_node_type_geo_edge_split();
register_node_type_geo_transform();
@@ -4690,9 +4737,11 @@ static void registerGeometryNodes(void)
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
register_node_type_geo_object_info();
- register_node_type_geo_random_attribute();
+ register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_math();
register_node_type_geo_join_geometry();
+ register_node_type_geo_attribute_mix();
+ register_node_type_geo_attribute_color_ramp();
}
static void registerFunctionNodes(void)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d747da2213e..8764232e56b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -38,6 +38,7 @@
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_defaults.h"
+#include "DNA_dynamicpaint_types.h"
#include "DNA_effect_types.h"
#include "DNA_fluid_types.h"
#include "DNA_gpencil_modifier_types.h"
@@ -1325,7 +1326,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
if (ob->type == OB_POINTCLOUD) {
- return (mti->modifyPointCloud != NULL);
+ return (mti->modifyGeometrySet != NULL);
}
if (ob->type == OB_VOLUME) {
return (mti->modifyVolume != NULL);
@@ -2208,7 +2209,9 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
BLI_listbase_clear(&psysn->childcachebufs);
if (flag & LIB_ID_CREATE_NO_MAIN) {
- BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
+ /* XXX Disabled, fails when evaluating depsgraph after copying ID with no main for preview
+ * creation. */
+ // BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
psysn->flag |= PSYS_SHARED_CACHES;
BLI_assert(psysn->pointcache != NULL);
}
@@ -5217,8 +5220,11 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
AnimData *adt = ob->adt;
FCurve *fcu;
- char pattern[MAX_NAME + 16];
- BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md->name);
+ char md_name_esc[sizeof(md->name) * 2];
+ BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc));
+
+ char pattern[sizeof(md_name_esc) + 16];
+ BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md_name_esc);
/* action - check for F-Curves with paths containing 'modifiers[' */
if (adt->action) {
@@ -5260,8 +5266,11 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
AnimData *adt = ob->adt;
FCurve *fcu;
- char pattern[MAX_NAME + 32];
- BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+ char md_name_esc[sizeof(md->name) * 2];
+ BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc));
+
+ char pattern[sizeof(md_name_esc) + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md_name_esc);
/* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
if (adt->action) {
@@ -5295,8 +5304,11 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
AnimData *adt = ob->adt;
FCurve *fcu;
- char pattern[MAX_NAME + 32];
- BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+ char fx_name_esc[sizeof(fx->name) * 2];
+ BLI_str_escape(fx_name_esc, fx->name, sizeof(fx_name_esc));
+
+ char pattern[sizeof(fx_name_esc) + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx_name_esc);
/* action - check for F-Curves with paths containing string[' */
if (adt->action) {
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index d5434710e23..8fa708f31cb 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -816,15 +816,13 @@ static void make_duplis_instances_component(const DupliContext *ctx)
float(*positions)[3];
float(*rotations)[3];
float(*scales)[3];
- Object **objects;
+ InstancedData *instanced_data;
const int amount = BKE_geometry_set_instances(
- ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &objects);
+ ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &instanced_data);
for (int i = 0; i < amount; i++) {
- Object *object = objects[i];
- if (object == NULL) {
- continue;
- }
+ InstancedData *data = &instanced_data[i];
+
float scale_matrix[4][4];
size_to_mat4(scale_matrix, scales[i]);
float rotation_matrix[4][4];
@@ -833,14 +831,43 @@ static void make_duplis_instances_component(const DupliContext *ctx)
mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix);
copy_v3_v3(instance_offset_matrix[3], positions[i]);
- float matrix[4][4];
- mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix);
- make_dupli(ctx, object, matrix, i);
+ if (data->type == INSTANCE_DATA_TYPE_OBJECT) {
+ Object *object = data->data.object;
+ if (object != NULL) {
+ float matrix[4][4];
+ mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix);
+ make_dupli(ctx, object, matrix, i);
+
+ float space_matrix[4][4];
+ mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat);
+ mul_m4_m4_pre(space_matrix, ctx->object->obmat);
+ make_recursive_duplis(ctx, object, space_matrix, i);
+ }
+ }
+ else if (data->type == INSTANCE_DATA_TYPE_COLLECTION) {
+ Collection *collection = data->data.collection;
+ if (collection != NULL) {
+ float collection_matrix[4][4];
+ unit_m4(collection_matrix);
+ sub_v3_v3(collection_matrix[3], collection->instance_offset);
+ mul_m4_m4_pre(collection_matrix, instance_offset_matrix);
+ mul_m4_m4_pre(collection_matrix, ctx->object->obmat);
+
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, object, mode) {
+ if (object == ctx->object) {
+ continue;
+ }
+
+ float instance_matrix[4][4];
+ mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat);
- float space_matrix[4][4];
- mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat);
- mul_m4_m4_pre(space_matrix, ctx->object->obmat);
- make_recursive_duplis(ctx, object, space_matrix, i);
+ make_dupli(ctx, object, instance_matrix, i);
+ make_recursive_duplis(ctx, object, collection_matrix, i);
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ }
}
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 915ee56e2f7..1b4dc98252a 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -28,6 +28,7 @@
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index d516de535f9..dce45f44583 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -41,6 +41,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_force_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 98a55c3de95..6e0965650d3 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -25,6 +25,7 @@
#include "BLI_noise.h"
#include "DNA_material_types.h"
+#include "DNA_object_types.h"
#include "BKE_colortools.h"
#include "BKE_particle.h"
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 194593be4ff..c3cc9136057 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -40,6 +40,7 @@
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
+#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 35265cf8b68..71df28c8b42 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -34,6 +34,7 @@
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
+#include "DNA_cloth_types.h"
#include "DNA_curve_types.h"
#include "DNA_listBase.h"
#include "DNA_mesh_types.h"
@@ -4978,6 +4979,24 @@ void particle_system_update(struct Depsgraph *depsgraph,
/* ID looper */
+/* unfortunately PSys and modifier ID loopers are not directly compatible, so we need this struct
+ * and the callback below to map the former to the latter (thanks to psys embedding a Cloth
+ * modifier data struct now, for Hair physics simulations). */
+typedef struct ParticleSystemIDLoopForModifier {
+ ParticleSystem *psys;
+ ParticleSystemIDFunc func;
+ void *userdata;
+} ParticleSystemIDLoopForModifier;
+
+static void particlesystem_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ ParticleSystemIDLoopForModifier *data = (ParticleSystemIDLoopForModifier *)user_data;
+ data->func(data->psys, id_pointer, data->userdata, cb_flag);
+}
+
void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata)
{
ParticleTarget *pt;
@@ -4986,6 +5005,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
+ if (psys->clmd != NULL) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(psys->clmd->modifier.type);
+
+ if (mti->foreachIDLink != NULL) {
+ ParticleSystemIDLoopForModifier data = {.psys = psys, .func = func, .userdata = userdata};
+ mti->foreachIDLink(
+ &psys->clmd->modifier, NULL, particlesystem_modifiersForeachIDLink, &data);
+ }
+ }
+
for (pt = psys->targets.first; pt; pt = pt->next) {
func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
}
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 5f6685817b9..7bd14e80333 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -365,12 +365,31 @@ static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
continue;
}
- if (mti->modifyPointCloud) {
- mti->modifyPointCloud(md, &mectx, &geometry_set);
+ if (mti->modifyGeometrySet) {
+ mti->modifyGeometrySet(md, &mectx, &geometry_set);
}
}
}
+static PointCloud *take_pointcloud_ownership_from_geometry_set(GeometrySet &geometry_set)
+{
+ if (!geometry_set.has<PointCloudComponent>()) {
+ return nullptr;
+ }
+ PointCloudComponent &pointcloud_component =
+ geometry_set.get_component_for_write<PointCloudComponent>();
+ PointCloud *pointcloud = pointcloud_component.release();
+ if (pointcloud != nullptr) {
+ /* Add back, but as read-only non-owning component. */
+ pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
+ }
+ else {
+ /* The component was empty, we can also remove it. */
+ geometry_set.remove<PointCloudComponent>();
+ }
+ return pointcloud;
+}
+
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
{
/* Free any evaluated data and restore original data. */
@@ -382,10 +401,17 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene
GeometryOwnershipType::ReadOnly);
pointcloud_evaluate_modifiers(depsgraph, scene, object, geometry_set);
+ PointCloud *pointcloud_eval = take_pointcloud_ownership_from_geometry_set(geometry_set);
+
+ /* If the geometry set did not contain a point cloud, we still create an empty one. */
+ if (pointcloud_eval == nullptr) {
+ pointcloud_eval = BKE_pointcloud_new_nomain(0);
+ }
+
/* Assign evaluated object. */
- PointCloud *dummy_pointcloud = BKE_pointcloud_new_nomain(0);
- BKE_object_eval_assign_data(object, &dummy_pointcloud->id, true);
- object->runtime.geometry_set_eval = new GeometrySet(geometry_set);
+ const bool eval_is_owned = pointcloud_eval != pointcloud;
+ BKE_object_eval_assign_data(object, &pointcloud_eval->id, eval_is_owned);
+ object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set));
}
/* Draw Cache */
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
new file mode 100644
index 00000000000..8dcf6de164a
--- /dev/null
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -0,0 +1,119 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * User defined asset library API.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_appdir.h"
+#include "BKE_preferences.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_userdef_types.h"
+
+#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
+
+/* -------------------------------------------------------------------- */
+/** \name Asset Libraries
+ * \{ */
+
+bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef,
+ const char *name,
+ const char *path)
+{
+ bUserAssetLibrary *library = MEM_callocN(sizeof(*library), "bUserAssetLibrary");
+
+ BLI_addtail(&userdef->asset_libraries, library);
+
+ if (name) {
+ BKE_preferences_asset_library_name_set(userdef, library, name);
+ }
+ if (path) {
+ BLI_strncpy(library->path, path, sizeof(library->path));
+ }
+
+ return library;
+}
+
+void BKE_preferences_asset_library_name_set(UserDef *userdef,
+ bUserAssetLibrary *library,
+ const char *name)
+{
+ BLI_strncpy_utf8(library->name, name, sizeof(library->name));
+ BLI_uniquename(&userdef->asset_libraries,
+ library,
+ name,
+ '.',
+ offsetof(bUserAssetLibrary, name),
+ sizeof(library->name));
+}
+
+/**
+ * Unlink and free a library preference member.
+ * \note Free's \a library itself.
+ */
+void BKE_preferences_asset_library_remove(UserDef *userdef, bUserAssetLibrary *library)
+{
+ BLI_freelinkN(&userdef->asset_libraries, library);
+}
+
+bUserAssetLibrary *BKE_preferences_asset_library_find_from_index(const UserDef *userdef, int index)
+{
+ return BLI_findlink(&userdef->asset_libraries, index);
+}
+
+bUserAssetLibrary *BKE_preferences_asset_library_find_from_name(const UserDef *userdef,
+ const char *name)
+{
+ return BLI_findstring(&userdef->asset_libraries, name, offsetof(bUserAssetLibrary, name));
+}
+
+int BKE_preferences_asset_library_get_index(const UserDef *userdef,
+ const bUserAssetLibrary *library)
+{
+ return BLI_findindex(&userdef->asset_libraries, library);
+}
+
+void BKE_preferences_asset_library_default_add(UserDef *userdef)
+{
+ char documents_path[FILE_MAXDIR];
+
+ /* No home or documents path found, not much we can do. */
+ if (!BKE_appdir_folder_documents(documents_path) || !documents_path[0]) {
+ return;
+ }
+
+ bUserAssetLibrary *library = BKE_preferences_asset_library_add(userdef, DATA_("Default"), NULL);
+
+ /* Add new "Default" library under '[doc_path]/Blender/Assets'. */
+ BLI_path_join(
+ library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index bed10df5ace..cc192c1c3c0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -37,6 +37,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_mask_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -47,6 +48,7 @@
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_text_types.h"
+#include "DNA_vfont_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -220,6 +222,7 @@ static void scene_init_data(ID *id)
/* Curve Profile */
scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
+ scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init();
for (size_t i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
scene->orientation_slots[i].index_custom = -1;
@@ -860,6 +863,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
if (tos->custom_bevel_profile_preset) {
BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset);
}
+ if (tos->sequencer_tool_settings) {
+ BLO_write_struct(writer, SequencerToolSettings, tos->sequencer_tool_settings);
+ }
BKE_paint_blend_write(writer, &tos->imapaint.paint);
@@ -1119,6 +1125,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
if (sce->toolsettings->custom_bevel_profile_preset) {
BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset);
}
+
+ BLO_read_data_address(reader, &sce->toolsettings->sequencer_tool_settings);
}
if (sce->ed) {
@@ -1790,6 +1798,8 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->gp_sculpt.cur_primitive = BKE_curvemapping_copy(ts->gp_sculpt.cur_primitive);
ts->custom_bevel_profile_preset = BKE_curveprofile_copy(ts->custom_bevel_profile_preset);
+
+ ts->sequencer_tool_settings = SEQ_tool_settings_copy(ts->sequencer_tool_settings);
return ts;
}
@@ -1848,6 +1858,10 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_curveprofile_free(toolsettings->custom_bevel_profile_preset);
}
+ if (toolsettings->sequencer_tool_settings) {
+ SEQ_tool_settings_free(toolsettings->sequencer_tool_settings);
+ }
+
MEM_freeN(toolsettings);
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 355db8f0d60..52c41c9fd05 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
@@ -1265,6 +1266,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area)
if (sfile->params) {
BLO_write_struct(writer, FileSelectParams, sfile->params);
}
+ if (sfile->asset_params) {
+ BLO_write_struct(writer, FileAssetSelectParams, sfile->asset_params);
+ }
}
else if (sl->spacetype == SPACE_SEQ) {
BLO_write_struct(writer, SpaceSeq, sl);
@@ -1662,11 +1666,14 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
* plus, it isn't saved to files yet!
*/
sfile->folders_prev = sfile->folders_next = NULL;
+ BLI_listbase_clear(&sfile->folder_histories);
sfile->files = NULL;
sfile->layout = NULL;
sfile->op = NULL;
sfile->previews_timer = NULL;
+ sfile->tags = 0;
BLO_read_data_address(reader, &sfile->params);
+ BLO_read_data_address(reader, &sfile->asset_params);
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -1750,8 +1757,11 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
}
break;
}
- case SPACE_FILE:
+ case SPACE_FILE: {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES;
break;
+ }
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
bDopeSheet *ads = &saction->ads;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 25d812884bc..736acd76dfd 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -52,6 +52,7 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 8b66b1fc628..5bcc1a9553a 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -135,13 +135,19 @@ static void sound_foreach_cache(ID *id,
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
bSound *sound = (bSound *)id;
- if (sound->id.us > 0 || BLO_write_is_undo(writer)) {
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (sound->id.us > 0 || is_undo) {
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
sound->tags = 0;
sound->handle = NULL;
sound->playback_handle = NULL;
sound->spinlock = NULL;
+ /* Do not store packed files in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(sound) && !is_undo) {
+ sound->packedfile = NULL;
+ }
+
/* write LibData */
BLO_write_id_struct(writer, bSound, id_address, &sound->id);
BKE_id_blend_write(writer, &sound->id);
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 93795af7cd7..9ef2e818293 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -459,12 +459,14 @@ bool BKE_text_reload(Text *text)
return true;
}
-/** Load a text file.
+/**
+ * Load a text file.
*
- * \param is_internal If \a true, this text data-block only exists in memory, not as a file on
- * disk.
+ * \param is_internal: If \a true, this text data-block only exists in memory,
+ * not as a file on disk.
*
- * \note: text data-blocks have no user by default, only the 'real user' flag. */
+ * \note text data-blocks have no user by default, only the 'real user' flag.
+ */
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
unsigned char *buffer;
@@ -520,7 +522,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
/** Load a text file.
*
- * \note: text data-blocks have no user by default, only the 'real user' flag. */
+ * \note Text data-blocks have no user by default, only the 'real user' flag.
+ */
Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
{
return BKE_text_load_ex(bmain, file, relpath, false);
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 11aa9597740..67727d87161 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -561,10 +561,16 @@ static void volume_foreach_cache(ID *id,
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Volume *volume = (Volume *)id;
- if (volume->id.us > 0 || BLO_write_is_undo(writer)) {
+ const bool is_undo = BLO_write_is_undo(writer);
+ if (volume->id.us > 0 || is_undo) {
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
volume->runtime.grids = nullptr;
+ /* Do not store packed files in case this is a library override ID. */
+ if (ID_IS_OVERRIDE_LIBRARY(volume) && !is_undo) {
+ volume->packedfile = nullptr;
+ }
+
/* write LibData */
BLO_write_id_struct(writer, Volume, id_address, &volume->id);
BKE_id_blend_write(writer, &volume->id);