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.c4
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/anim_data.c2
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c3
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c9
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c4
-rw-r--r--source/blender/blenkernel/intern/blendfile.c25
-rw-r--r--source/blender/blenkernel/intern/boids.c5
-rw-r--r--source/blender/blenkernel/intern/bpath.c18
-rw-r--r--source/blender/blenkernel/intern/brush.c56
-rw-r--r--source/blender/blenkernel/intern/collection.c101
-rw-r--r--source/blender/blenkernel/intern/colortools.c28
-rw-r--r--source/blender/blenkernel/intern/constraint.c54
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c8
-rw-r--r--source/blender/blenkernel/intern/curve.c6
-rw-r--r--source/blender/blenkernel/intern/curveprofile.c287
-rw-r--r--source/blender/blenkernel/intern/customdata.c54
-rw-r--r--source/blender/blenkernel/intern/derived_node_tree.cc55
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c2
-rw-r--r--source/blender/blenkernel/intern/editmesh.c11
-rw-r--r--source/blender/blenkernel/intern/effect.c42
-rw-r--r--source/blender/blenkernel/intern/fcurve.c6
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c14
-rw-r--r--source/blender/blenkernel/intern/fluid.c100
-rw-r--r--source/blender/blenkernel/intern/font.c16
-rw-r--r--source/blender/blenkernel/intern/gpencil.c66
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c3
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c406
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c60
-rw-r--r--source/blender/blenkernel/intern/idprop.c4
-rw-r--r--source/blender/blenkernel/intern/image.c46
-rw-r--r--source/blender/blenkernel/intern/image_save.c6
-rw-r--r--source/blender/blenkernel/intern/lib_id.c73
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c9
-rw-r--r--source/blender/blenkernel/intern/lib_override.c215
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c5
-rw-r--r--source/blender/blenkernel/intern/library.c18
-rw-r--r--source/blender/blenkernel/intern/main.c23
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c80
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c31
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c31
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/movieclip.c26
-rw-r--r--source/blender/blenkernel/intern/node.c4
-rw-r--r--source/blender/blenkernel/intern/node_tree_ref.cc25
-rw-r--r--source/blender/blenkernel/intern/object.c388
-rw-r--r--source/blender/blenkernel/intern/object_update.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c30
-rw-r--r--source/blender/blenkernel/intern/paint.c36
-rw-r--r--source/blender/blenkernel/intern/particle.c3
-rw-r--r--source/blender/blenkernel/intern/particle_system.c9
-rw-r--r--source/blender/blenkernel/intern/pbvh.c31
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h3
-rw-r--r--source/blender/blenkernel/intern/pointcache.c35
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c7
-rw-r--r--source/blender/blenkernel/intern/scene.c71
-rw-r--r--source/blender/blenkernel/intern/screen.c26
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c8
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/sequencer.c631
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c20
-rw-r--r--source/blender/blenkernel/intern/simulation.cc17
-rw-r--r--source/blender/blenkernel/intern/softbody.c5
-rw-r--r--source/blender/blenkernel/intern/sound.c8
-rw-r--r--source/blender/blenkernel/intern/studiolight.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c38
-rw-r--r--source/blender/blenkernel/intern/text.c71
67 files changed, 2208 insertions, 1284 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index b4e2cd772c9..8a5be6b9cb3 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -1669,7 +1669,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
Mesh *me_orig = mesh_input;
if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) {
- BKE_mesh_runtime_ensure_edit_data(me_orig);
+ 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);
}
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index c776f0d077d..b35d2183408 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -939,7 +939,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
BKE_constraints_free_ex(&pchan->constraints, do_id_user);
if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
+ IDP_FreeProperty_ex(pchan->prop, do_id_user);
pchan->prop = NULL;
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index cbb34cbee30..841fdaa3b2c 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -399,6 +399,8 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
if (ntree) {
BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
}
+ /* Note that collections are not animatable currently, so no need to handle scenes' master
+ * collection here. */
}
/* Merge copies of the data from the src AnimData into the destination AnimData */
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index e757e30e524..44b50ab96d3 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -349,8 +349,7 @@ static void armature_vert_task_with_dvert(const ArmatureUserdata *data,
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
}
}
- /* if there are vertexgroups but not groups with bones
- * (like for softbody groups) */
+ /* If there are vertex-groups but not groups with bones (like for soft-body groups). */
if (deformed == 0 && use_envelope) {
for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) {
if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index 4d27621a861..e950e94655a 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -72,9 +72,10 @@ void BKE_copybuffer_tag_ID(ID *id)
*/
bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
{
- const int write_flags = G_FILE_RELATIVE_REMAP;
+ const int write_flags = 0;
+ const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE;
- bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
+ bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, remap_mode, reports);
BKE_blendfile_write_partial_end(bmain_src);
@@ -99,7 +100,7 @@ bool BKE_copybuffer_read(Main *bmain_dst,
BKE_main_lib_objects_recalc_all(bmain_dst);
IMB_colormanagement_check_file_config(bmain_dst);
/* Append, rather than linking. */
- Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath));
+ Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs));
BKE_library_make_local(bmain_dst, lib, NULL, true, false);
/* Important we unset, otherwise these object wont
* link into other scenes from this blend file.
@@ -154,7 +155,7 @@ int BKE_copybuffer_paste(bContext *C,
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
- lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath));
+ lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs));
BKE_library_make_local(bmain, lib, NULL, true, false);
/* important we unset, otherwise these object wont
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index ab382d0e8ff..a6f84f3c3a4 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -109,7 +109,6 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
static int counter = 0;
char filename[FILE_MAX];
char numstr[32];
- int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */
/* Calculate current filename. */
counter++;
@@ -118,7 +117,8 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), numstr);
- /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL);
+ /* success = */ /* UNUSED */ BLO_write_file(
+ bmain, filename, G.fileflags, &(const struct BlendFileWriteParams){0}, NULL);
BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index ef474022f19..ee60bf79611 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -646,7 +646,13 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
bool ok = false;
- if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) {
+ if (BLO_write_file(mainb,
+ filepath,
+ 0,
+ &(const struct BlendFileWriteParams){
+ .use_userdef = true,
+ },
+ reports)) {
ok = true;
}
@@ -768,7 +774,7 @@ WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepat
bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
{
- int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY);
+ const int fileflags = G.fileflags & ~G_FILE_NO_UI;
bool retval = false;
BKE_blendfile_write_partial_begin(bmain);
@@ -777,7 +783,8 @@ bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, Rep
BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
}
- if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ if (BKE_blendfile_write_partial(
+ bmain, filepath, fileflags, BLO_WRITE_PATH_REMAP_NONE, reports)) {
retval = true;
}
@@ -829,11 +836,13 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
}
/**
+ * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
* \return Success.
*/
bool BKE_blendfile_write_partial(Main *bmain_src,
const char *filepath,
const int write_flags,
+ const int remap_mode,
ReportList *reports)
{
Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
@@ -875,12 +884,18 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
* This happens because id_sort_by_name does not take into account
* string case or the library name, so the order is not strictly
* defined for two linked data-blocks with the same name! */
- if (write_flags & G_FILE_RELATIVE_REMAP) {
+ if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag);
}
/* save the buffer */
- retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
+ retval = BLO_write_file(bmain_dst,
+ filepath,
+ write_flags,
+ &(const struct BlendFileWriteParams){
+ .remap_mode = remap_mode,
+ },
+ reports);
if (path_list_backup) {
BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup);
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 6197b9dbefd..d5064629451 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -218,7 +218,7 @@ static int rule_avoid_collision(BoidRule *rule,
BoidValues *val,
ParticleData *pa)
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision *)rule;
KDTreeNearest_3d *ptn = NULL;
ParticleTarget *pt;
@@ -854,7 +854,7 @@ static Object *boid_find_ground(BoidBrainData *bbd,
float ground_co[3],
float ground_nor[3])
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
BoidParticle *bpa = pa->boid;
if (bpa->data.mode == eBoidMode_Climbing) {
@@ -1388,6 +1388,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
bbd->part->effector_weights,
&epoint,
force,
+ NULL,
NULL);
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index f0e23ddad41..10783c741b6 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -564,8 +564,8 @@ void BKE_bpath_traverse_id(
* don't make sense to add directories to until the image has been saved
* once to give it a meaningful value. */
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) &&
- ima->name[0]) {
- if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
+ ima->filepath[0]) {
+ if (rewrite_path_fixed(ima->filepath, visit_cb, absbase, bpath_user_data)) {
if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
if (!BKE_image_has_packedfile(ima) &&
/* image may have been painted onto (and not saved, T44543) */
@@ -643,7 +643,7 @@ void BKE_bpath_traverse_id(
case ID_SO: {
bSound *sound = (bSound *)id;
if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data);
+ rewrite_path_fixed(sound->filepath, visit_cb, absbase, bpath_user_data);
}
break;
}
@@ -655,15 +655,15 @@ void BKE_bpath_traverse_id(
break;
}
case ID_TXT:
- if (((Text *)id)->name) {
- rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data);
+ if (((Text *)id)->filepath) {
+ rewrite_path_alloc(&((Text *)id)->filepath, visit_cb, absbase, bpath_user_data);
}
break;
case ID_VF: {
VFont *vfont = (VFont *)id;
if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (BKE_vfont_is_builtin(vfont) == false) {
- rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data);
+ rewrite_path_fixed(((VFont *)id)->filepath, visit_cb, absbase, bpath_user_data);
}
}
break;
@@ -756,15 +756,15 @@ void BKE_bpath_traverse_id(
Library *lib = (Library *)id;
/* keep packedfile paths always relative to the blend */
if (lib->packedfile == NULL) {
- if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) {
- BKE_library_filepath_set(bmain, lib, lib->name);
+ if (rewrite_path_fixed(lib->filepath, visit_cb, absbase, bpath_user_data)) {
+ BKE_library_filepath_set(bmain, lib, lib->filepath);
}
}
break;
}
case ID_MC: {
MovieClip *clip = (MovieClip *)id;
- rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
+ rewrite_path_fixed(clip->filepath, visit_cb, absbase, bpath_user_data);
break;
}
case ID_CF: {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 3241518cae5..a8f52593429 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -248,6 +248,7 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(crease_pinch_factor);
FROM_DEFAULT(normal_radius_factor);
FROM_DEFAULT(area_radius_factor);
+ FROM_DEFAULT(disconnected_distance_max);
FROM_DEFAULT(sculpt_plane);
FROM_DEFAULT(plane_offset);
FROM_DEFAULT(clone.alpha);
@@ -493,7 +494,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->preset_type = type;
/* Set vertex mix factor. */
- brush->gpencil_settings->vertex_mode = GPPAINT_MODE_STROKE;
+ brush->gpencil_settings->vertex_mode = GPPAINT_MODE_BOTH;
brush->gpencil_settings->vertex_factor = 1.0f;
switch (type) {
@@ -1185,6 +1186,11 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r
if (reset || brush_prev == NULL) {
BKE_paint_brush_set(paint, deft_draw);
}
+ else {
+ if (brush_prev != NULL) {
+ BKE_paint_brush_set(paint, brush_prev);
+ }
+ }
}
/* Create a set of grease pencil Vertex Paint presets. */
@@ -1227,6 +1233,11 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
if (reset || brush_prev == NULL) {
BKE_paint_brush_set(vertexpaint, deft_vertex);
}
+ else {
+ if (brush_prev != NULL) {
+ BKE_paint_brush_set(vertexpaint, brush_prev);
+ }
+ }
}
/* Create a set of grease pencil Sculpt Paint presets. */
@@ -1297,6 +1308,11 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
if (reset || brush_prev == NULL) {
BKE_paint_brush_set(sculptpaint, deft_sculpt);
}
+ else {
+ if (brush_prev != NULL) {
+ BKE_paint_brush_set(sculptpaint, brush_prev);
+ }
+ }
}
/* Create a set of grease pencil Weight Paint presets. */
@@ -1318,6 +1334,11 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
if (reset || brush_prev == NULL) {
BKE_paint_brush_set(weightpaint, deft_weight);
}
+ else {
+ if (brush_prev != NULL) {
+ BKE_paint_brush_set(weightpaint, brush_prev);
+ }
+ }
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
@@ -1538,7 +1559,7 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_POSE:
br->pose_smooth_iterations = 4;
br->pose_ik_segments = 1;
- br->flag2 |= BRUSH_POSE_IK_ANCHORED;
+ br->flag2 |= BRUSH_POSE_IK_ANCHORED | BRUSH_USE_CONNECTED_ONLY;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
@@ -1570,6 +1591,24 @@ void BKE_brush_sculpt_reset(Brush *br)
br->alpha = 1.0f;
br->height = 0.05f;
break;
+ case SCULPT_TOOL_PAINT:
+ br->hardness = 0.4f;
+ br->spacing = 10;
+ br->alpha = 0.6f;
+ br->flow = 1.0f;
+ br->tip_scale_x = 1.0f;
+ br->tip_roundness = 1.0f;
+ br->density = 1.0f;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ zero_v3(br->rgb);
+ break;
+ case SCULPT_TOOL_SMEAR:
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ break;
default:
break;
}
@@ -1629,14 +1668,15 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_SIMPLIFY:
+ case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_MASK:
case SCULPT_TOOL_DRAW_FACE_SETS:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.750000;
- br->sub_col[1] = 0.750000;
- br->sub_col[2] = 0.750000;
+ br->add_col[0] = 0.75f;
+ br->add_col[1] = 0.75f;
+ br->add_col[2] = 0.75f;
+ br->sub_col[0] = 0.75f;
+ br->sub_col[1] = 0.75f;
+ br->sub_col[2] = 0.75f;
break;
case SCULPT_TOOL_CLOTH:
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 6f63da18a22..080d61f1500 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -28,6 +28,7 @@
#include "BLI_threads.h"
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_collection.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
@@ -326,16 +327,16 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
static Collection *collection_duplicate_recursive(Main *bmain,
Collection *parent,
Collection *collection_old,
- const bool do_hierarchy,
- const bool do_objects,
- const bool do_obdata)
+ const eDupli_ID_Flags duplicate_flags,
+ const eLibIDDuplicateFlags duplicate_options)
{
Collection *collection_new;
bool do_full_process = false;
- const int object_dupflag = (do_obdata) ? U.dupflag : 0;
const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0;
const bool is_collection_liboverride = ID_IS_OVERRIDE_LIBRARY(collection_old);
+ const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0;
+
if (is_collection_master) {
/* We never duplicate master collections here, but we can still deep-copy their objects and
* collections. */
@@ -343,15 +344,9 @@ static Collection *collection_duplicate_recursive(Main *bmain,
collection_new = collection_old;
do_full_process = true;
}
- else if (!do_hierarchy || collection_old->id.newid == NULL) {
- BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new);
-
- /* Copying add one user by default, need to get rid of that one. */
- id_us_min(&collection_new->id);
-
- if (do_hierarchy) {
- ID_NEW_SET(collection_old, collection_new);
- }
+ else if (collection_old->id.newid == NULL) {
+ collection_new = (Collection *)BKE_id_copy_for_duplicate(
+ bmain, (ID *)collection_old, is_collection_liboverride, duplicate_flags);
do_full_process = true;
}
else {
@@ -376,7 +371,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
/* If we are not doing any kind of deep-copy, we can return immediately.
* False do_full_process means collection_old had already been duplicated,
* no need to redo some deep-copy on it. */
- if (!do_hierarchy || !do_full_process) {
+ if (!do_full_process) {
return collection_new;
}
@@ -394,8 +389,8 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
if (ob_new == NULL) {
- ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag);
- ID_NEW_SET(ob_old, ob_new);
+ ob_new = BKE_object_duplicate(
+ bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS);
}
collection_object_add(bmain, collection_new, ob_new, 0, true);
@@ -413,7 +408,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
collection_duplicate_recursive(
- bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata);
+ bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options);
collection_child_remove(collection_new, child_collection_old);
}
@@ -421,56 +416,54 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
/**
- * Makes a standard (aka shallow) ID copy of a Collection.
- *
- * Add a new collection in the same level as the old one, link any nested collections
- * and finally link the objects to the new collection (as opposed to copying them).
- */
-Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
-{
- return BKE_collection_duplicate(bmain, parent, collection, false, false, false);
-}
-
-/**
- * Make either a shallow copy, or deeper duplicate of given collection.
+ * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
*
- * If \a do_hierarchy and \a do_deep_copy are false, this is a regular (shallow) ID copy.
- *
- * \warning If any 'deep copy' behavior is enabled,
- * this functions will clear all \a bmain id.idnew pointers.
- *
- * \param do_hierarchy: If true, it will recursively make shallow copies of children collections.
- * \param do_objects: If true, it will also make duplicates of objects.
- * This one does nothing if \a do_hierarchy is not set.
- * \param do_obdata: If true, it will also make deep duplicates of objects,
- * using behavior defined in user settings (#U.dupflag).
- * This one does nothing if \a do_hierarchy and \a do_objects are not set.
+ * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
+ * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
+ * responsible to reconstruct collection dependencies information's
+ * (i.e. call #BKE_main_collection_sync).
*/
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
- const bool do_hierarchy,
- const bool do_objects,
- const bool do_obdata)
+ eDupli_ID_Flags duplicate_flags,
+ eLibIDDuplicateFlags duplicate_options)
{
- if (do_hierarchy) {
+ const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
+
+ if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
}
Collection *collection_new = collection_duplicate_recursive(
- bmain, parent, collection, do_hierarchy, do_objects, do_obdata);
-
- /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/
- BKE_libblock_relink_to_newid(&collection_new->id);
+ bmain, parent, collection, duplicate_flags, duplicate_options);
+
+ if (!is_subprocess) {
+ /* `collection_duplicate_recursive` will also tag our 'root' collection, which is not required
+ * unless its duplication is a sub-process of another one. */
+ collection_new->id.tag &= ~LIB_TAG_NEW;
+
+ /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/
+ BKE_libblock_relink_to_newid(&collection_new->id);
+
+#ifndef NDEBUG
+ /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (id_iter->tag & LIB_TAG_NEW) {
+ BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+#endif
- if (do_hierarchy) {
/* Cleanup. */
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
- }
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
+ }
return collection_new;
}
@@ -927,7 +920,7 @@ bool BKE_collection_object_remove(Main *bmain,
/**
* Remove object from all collections of scene
- * \param scene_collection_skip: Don't remove base from this collection.
+ * \param collection_skip: Don't remove base from this collection.
*/
static bool scene_collections_object_remove(
Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
@@ -1126,7 +1119,7 @@ static bool collection_find_instance_recursive(Collection *collection,
{
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
if (collection_object->ob != NULL &&
- /* Object from a given collection should never instanciate that collection either. */
+ /* Object from a given collection should never instantiate that collection either. */
ELEM(collection_object->ob->instance_collection, instance_collection, collection)) {
return true;
}
@@ -1153,7 +1146,7 @@ bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
}
}
- /* Find possible objects in collection or its children, that would instanciate the given ancestor
+ /* Find possible objects in collection or its children, that would instantiate the given ancestor
* collection (that would also make a fully invalid cycle of dependencies) .*/
return collection_find_instance_recursive(collection, new_ancestor);
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 3da384a2745..4f4eb8f9f9d 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -44,6 +44,8 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "BLO_read_write.h"
+
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -1238,6 +1240,32 @@ void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *
}
}
+void BKE_curvemapping_blend_write(BlendWriter *writer, const CurveMapping *cumap)
+{
+ BLO_write_struct(writer, CurveMapping, cumap);
+ BKE_curvemapping_curves_blend_write(writer, cumap);
+}
+
+void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping *cumap)
+{
+ for (int a = 0; a < CM_TOT; a++) {
+ BLO_write_struct_array(writer, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve);
+ }
+}
+
+/* cumap itself has been read already. */
+void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
+{
+ /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
+ cumap->flag &= ~CUMA_PREMULLED;
+
+ for (int a = 0; a < CM_TOT; a++) {
+ BLO_read_data_address(reader, &cumap->cm[a].curve);
+ cumap->cm[a].table = NULL;
+ cumap->cm[a].premultable = NULL;
+ }
+}
+
/* ***************** Histogram **************** */
#define INV_255 (1.f / 255.f)
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 050e8d434ae..06c28776840 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -5412,9 +5412,16 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
/* Set up a generic constraint data-block. */
con->type = type;
- con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+ con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
con->enforce = 1.0f;
+ /* Only open the main panel when constraints are created, not the sub-panels. */
+ con->ui_expand_flag = (1 << 0);
+ if (ELEM(type, CONSTRAINT_TYPE_ACTION, CONSTRAINT_TYPE_SPLINEIK)) {
+ /* Expand the two sub-panels in the cases where the main panel barely has any properties. */
+ con->ui_expand_flag |= (1 << 1) | (1 << 2);
+ }
+
/* Determine a basic name, and info */
if (cti) {
/* initialize constraint data */
@@ -5441,18 +5448,11 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
return con;
}
-/* if pchan is not NULL then assume we're adding a pose constraint */
-static bConstraint *add_new_constraint(Object *ob,
- bPoseChannel *pchan,
- const char *name,
- short type)
+/* Add a newly created constraint to the constraint list. */
+static void add_new_constraint_to_list(Object *ob, bPoseChannel *pchan, bConstraint *con)
{
- bConstraint *con;
ListBase *list;
- /* add the constraint */
- con = add_new_constraint_internal(name, type);
-
/* find the constraint stack - bone or object? */
list = (pchan) ? (&pchan->constraints) : (&ob->constraints);
@@ -5474,6 +5474,20 @@ static bConstraint *add_new_constraint(Object *ob,
/* make this constraint the active one */
BKE_constraints_active_set(list, con);
}
+}
+
+/* if pchan is not NULL then assume we're adding a pose constraint */
+static bConstraint *add_new_constraint(Object *ob,
+ bPoseChannel *pchan,
+ const char *name,
+ short type)
+{
+ bConstraint *con;
+
+ /* add the constraint */
+ con = add_new_constraint_internal(name, type);
+
+ add_new_constraint_to_list(ob, pchan, con);
/* set type+owner specific immutable settings */
/* TODO: does action constraint need anything here - i.e. spaceonce? */
@@ -5607,6 +5621,26 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const
return dst;
}
+/* Add a copy of the given constraint for the given bone */
+bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bConstraint *src)
+{
+ if (pchan == NULL) {
+ return NULL;
+ }
+
+ bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob));
+ add_new_constraint_to_list(ob, pchan, new_con);
+ return new_con;
+}
+
+/* Add a copy of the given constraint for the given object */
+bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
+{
+ bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob));
+ add_new_constraint_to_list(ob, NULL, new_con);
+ return new_con;
+}
+
/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 4d685a511fd..e4f851819a8 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -252,7 +252,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
}
/**
- * Returns an array of deform matrices for crazyspace correction,
+ * Returns an array of deform matrices for crazy-space correction,
* and the number of modifiers left.
*/
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
@@ -327,7 +327,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
}
/**
- * Crazyspace evaluation needs to have an object which has all the fields
+ * Crazy-space evaluation needs to have an object which has all the fields
* evaluated, but the mesh data being at undeformed state. This way it can
* re-apply modifiers and also have proper pointers to key data blocks.
*
@@ -455,8 +455,8 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
depsgraph, scene, object, deformmats, deformcos);
if (totleft) {
- /* there are deformation modifier which doesn't support deformation matrices
- * calculation. Need additional crazyspace correction */
+ /* There are deformation modifier which doesn't support deformation matrices calculation.
+ * Need additional crazy-space correction. */
Mesh *mesh = (Mesh *)object->data;
Mesh *mesh_eval = NULL;
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0b65f53708f..6b28297622c 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -4081,9 +4081,9 @@ void BKE_nurb_handle_calc(
/**
* Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
*
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually #SELECT, but may want to use a different one at times
+ * (if caller does not operate on selection).
*/
void BKE_nurb_handle_calc_ex(BezTriple *bezt,
BezTriple *prev,
diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c
index a748dfbab3e..6919d4fa10f 100644
--- a/source/blender/blenkernel/intern/curveprofile.c
+++ b/source/blender/blenkernel/intern/curveprofile.c
@@ -41,6 +41,8 @@
#include "BKE_curveprofile.h"
#include "BKE_fcurve.h"
+#include "BLO_read_write.h"
+
void BKE_curveprofile_free_data(CurveProfile *profile)
{
MEM_SAFE_FREE(profile->path);
@@ -63,6 +65,11 @@ void BKE_curveprofile_copy_data(CurveProfile *target, const CurveProfile *profil
target->path = MEM_dupallocN(profile->path);
target->table = MEM_dupallocN(profile->table);
target->segments = MEM_dupallocN(profile->segments);
+
+ /* Update the reference the points have to the profile. */
+ for (int i = 0; i < target->path_len; i++) {
+ target->path[i].profile = target;
+ }
}
CurveProfile *BKE_curveprofile_copy(const CurveProfile *profile)
@@ -76,6 +83,101 @@ CurveProfile *BKE_curveprofile_copy(const CurveProfile *profile)
}
/**
+ * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
+ *
+ * \param handle_1: Whether to move the 1st or 2nd control point.
+ * \param delta: The *relative* change in the handle's position.
+ * \note Requires #BKE_curveprofile_update call after.
+ * \return Whether the handle moved from its start position.
+ */
+bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
+ const bool handle_1,
+ const bool snap,
+ const float delta[2])
+{
+ short handle_type = (handle_1) ? point->h1 : point->h2;
+ float *handle_location = (handle_1) ? &point->h1_loc[0] : &point->h2_loc[0];
+
+ float start_position[2];
+ copy_v2_v2(start_position, handle_location);
+
+ /* Don't move the handle if it's not a free handle type. */
+ if (!ELEM(handle_type, HD_FREE, HD_ALIGN)) {
+ return false;
+ }
+
+ /* Move the handle. */
+ handle_location[0] += delta ? delta[0] : 0.0f;
+ handle_location[1] += delta ? delta[1] : 0.0f;
+ if (snap) {
+ handle_location[0] = 0.125f * roundf(8.0f * handle_location[0]);
+ handle_location[1] = 0.125f * roundf(8.0f * handle_location[1]);
+ }
+
+ /* Move the other handle if they are aligned. */
+ if (handle_type == HD_ALIGN) {
+ short other_handle_type = (handle_1) ? point->h2 : point->h1;
+ if (other_handle_type == HD_ALIGN) {
+ float *other_handle_location = (handle_1) ? &point->h2_loc[0] : &point->h1_loc[0];
+ other_handle_location[0] = 2.0f * point->x - handle_location[0];
+ other_handle_location[1] = 2.0f * point->y - handle_location[1];
+ }
+ }
+
+ if (!equals_v2v2(handle_location, start_position)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Moves a control point, accounting for clipping and snapping, and moving free handles.
+ *
+ * \param snap: Whether to snap the point to the grid
+ * \param delta: The *relative* change of the point's location.
+ * \return Whether the point moved from its start position.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
+bool BKE_curveprofile_move_point(struct CurveProfile *profile,
+ struct CurveProfilePoint *point,
+ const bool snap,
+ const float delta[2])
+{
+ float origx = point->x;
+ float origy = point->y;
+
+ point->x += delta[0];
+ point->y += delta[1];
+ if (snap) {
+ point->x = 0.125f * roundf(8.0f * point->x);
+ point->y = 0.125f * roundf(8.0f * point->y);
+ }
+
+ /* Clip here instead to test clipping here to stop handles from moving too. */
+ if (profile->flag & PROF_USE_CLIP) {
+ point->x = max_ff(point->x, profile->clip_rect.xmin);
+ point->x = min_ff(point->x, profile->clip_rect.xmax);
+ point->y = max_ff(point->y, profile->clip_rect.ymin);
+ point->y = min_ff(point->y, profile->clip_rect.ymax);
+ }
+
+ /* Also move free handles even when they aren't selected. */
+ if (ELEM(point->h1, HD_FREE, HD_ALIGN)) {
+ point->h1_loc[0] += point->x - origx;
+ point->h1_loc[1] += point->y - origy;
+ }
+ if (ELEM(point->h2, HD_FREE, HD_ALIGN)) {
+ point->h2_loc[0] += point->x - origx;
+ point->h2_loc[1] += point->y - origy;
+ }
+
+ if (point->x != origx || point->y != origy) {
+ return true;
+ }
+ return false;
+}
+
+/**
* Removes a specific point from the path of control points.
* \note Requires #BKE_curveprofile_update call after.
*/
@@ -98,8 +200,10 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi
uint i_delete = (uint)(point - profile->path);
/* Copy the before and after the deleted point. */
- memcpy(pts, profile->path, i_delete);
- memcpy(pts + i_delete, profile->path + i_delete + 1, (size_t)profile->path_len - i_delete - 1);
+ memcpy(pts, profile->path, sizeof(CurveProfilePoint) * i_delete);
+ memcpy(pts + i_delete,
+ profile->path + i_delete + 1,
+ sizeof(CurveProfilePoint) * (profile->path_len - i_delete - 1));
MEM_freeN(profile->path);
profile->path = pts;
@@ -178,12 +282,9 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
"profile path");
for (int i_new = 0, i_old = 0; i_new < profile->path_len; i_new++) {
if (i_new != i_insert) {
- /* Insert old points */
- new_pts[i_new].x = profile->path[i_old].x;
- new_pts[i_new].y = profile->path[i_old].y;
- new_pts[i_new].flag = profile->path[i_old].flag & ~PROF_SELECT; /* Deselect old points. */
- new_pts[i_new].h1 = profile->path[i_old].h1;
- new_pts[i_new].h2 = profile->path[i_old].h2;
+ /* Insert old points. */
+ memcpy(&new_pts[i_new], &profile->path[i_old], sizeof(CurveProfilePoint));
+ new_pts[i_new].flag &= ~PROF_SELECT; /* Deselect old points. */
i_old++;
}
else {
@@ -199,6 +300,8 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
else {
new_pt->h1 = new_pt->h2 = HD_AUTO;
}
+ /* Give new point a reference to the profile. */
+ new_pt->profile = profile;
}
}
@@ -210,35 +313,19 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
/**
* Sets the handle type of the selected control points.
- * \param type_1, type_2: Either HD_VECT or HD_AUTO. Handle types for the first and second handles.
- *
+ * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
* \note Requires #BKE_curveprofile_update call after.
*/
void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2)
{
for (int i = 0; i < profile->path_len; i++) {
- if (profile->path[i].flag & PROF_SELECT) {
- switch (type_1) {
- case HD_AUTO:
- profile->path[i].h1 = HD_AUTO;
- break;
- case HD_VECT:
- profile->path[i].h1 = HD_VECT;
- break;
- default:
- profile->path[i].h1 = HD_AUTO;
- break;
- }
- switch (type_2) {
- case HD_AUTO:
- profile->path[i].h2 = HD_AUTO;
- break;
- case HD_VECT:
- profile->path[i].h2 = HD_VECT;
- break;
- default:
- profile->path[i].h1 = HD_AUTO;
- break;
+ if (ELEM(profile->path[i].flag, PROF_SELECT, PROF_H1_SELECT, PROF_H2_SELECT)) {
+ profile->path[i].h1 = type_1;
+ profile->path[i].h2 = type_2;
+
+ if (type_1 == HD_ALIGN && type_2 == HD_ALIGN) {
+ /* Align the handles. */
+ BKE_curveprofile_move_handle(&profile->path[i], true, false, NULL);
}
}
}
@@ -259,11 +346,24 @@ void BKE_curveprofile_reverse(CurveProfile *profile)
"profile path");
/* Mirror the new points across the y = x line */
for (int i = 0; i < profile->path_len; i++) {
- new_pts[profile->path_len - i - 1].x = profile->path[i].y;
- new_pts[profile->path_len - i - 1].y = profile->path[i].x;
- new_pts[profile->path_len - i - 1].flag = profile->path[i].flag;
- new_pts[profile->path_len - i - 1].h1 = profile->path[i].h1;
- new_pts[profile->path_len - i - 1].h2 = profile->path[i].h2;
+ int i_reversed = profile->path_len - i - 1;
+ BLI_assert(i_reversed >= 0);
+ new_pts[i_reversed].x = profile->path[i].y;
+ new_pts[i_reversed].y = profile->path[i].x;
+ new_pts[i_reversed].flag = profile->path[i].flag;
+ new_pts[i_reversed].h1 = profile->path[i].h2;
+ new_pts[i_reversed].h2 = profile->path[i].h1;
+ new_pts[i_reversed].profile = profile;
+
+ /* Mirror free handles, they can't be recalculated. */
+ if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) {
+ new_pts[i_reversed].h1_loc[0] = profile->path[i].h2_loc[1];
+ new_pts[i_reversed].h1_loc[1] = profile->path[i].h2_loc[0];
+ }
+ if (ELEM(profile->path[i].h2, HD_FREE, HD_ALIGN)) {
+ new_pts[i_reversed].h2_loc[0] = profile->path[i].h1_loc[1];
+ new_pts[i_reversed].h2_loc[1] = profile->path[i].h1_loc[0];
+ }
}
/* Free the old points and use the new ones */
@@ -446,6 +546,13 @@ void BKE_curveprofile_reset(CurveProfile *profile)
break;
}
+ profile->flag &= ~PROF_DIRTY_PRESET;
+
+ /* Ensure each point has a reference to the profile. */
+ for (int i = 0; i < profile->path_len; i++) {
+ profile->path[i].profile = profile;
+ }
+
if (profile->table) {
MEM_freeN(profile->table);
profile->table = NULL;
@@ -463,7 +570,7 @@ static bool is_curved_edge(BezTriple *bezt, int i)
/**
* Used to set bezier handle locations in the sample creation process. Reduced copy of
- * #calchandleNurb_intern code in curve.c.
+ * #calchandleNurb_intern code in curve.c, mostly changed by removing the third dimension.
*/
static void calchandle_profile(BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
{
@@ -598,7 +705,7 @@ static int sort_points_curvature(const void *in_a, const void *in_b)
* this is true and there are only vector edges the straight edges will still be sampled.
* \param r_samples: An array of points to put the sampled positions. Must have length n_segments.
* \return r_samples: Fill the array with the sampled locations and if the point corresponds
- * to a control point, its handle type
+ * to a control point, its handle type.
*/
void BKE_curveprofile_create_samples(CurveProfile *profile,
int n_segments,
@@ -619,21 +726,33 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
for (i = 0; i < totpoints; i++) {
bezt[i].vec[1][0] = profile->path[i].x;
bezt[i].vec[1][1] = profile->path[i].y;
- bezt[i].h1 = (profile->path[i].h1 == HD_VECT) ? HD_VECT : HD_AUTO;
- bezt[i].h2 = (profile->path[i].h2 == HD_VECT) ? HD_VECT : HD_AUTO;
- }
- /* Give the first and last bezier points the same handle type as their neighbors. */
- if (totpoints > 2) {
- bezt[0].h1 = bezt[0].h2 = bezt[1].h1;
- bezt[totpoints - 1].h1 = bezt[totpoints - 1].h2 = bezt[totpoints - 2].h2;
+ bezt[i].h1 = profile->path[i].h1;
+ bezt[i].h2 = profile->path[i].h2;
+ /* Copy handle locations if the handle type is free. */
+ if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) {
+ bezt[i].vec[0][0] = profile->path[i].h1_loc[0];
+ bezt[i].vec[0][1] = profile->path[i].h1_loc[1];
+ }
+ if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) {
+ bezt[i].vec[2][0] = profile->path[i].h2_loc[0];
+ bezt[i].vec[2][1] = profile->path[i].h2_loc[1];
+ }
}
- /* Get handle positions for the bezier points. */
+ /* Get handle positions for the non-free bezier points. */
calchandle_profile(&bezt[0], NULL, &bezt[1]);
for (i = 1; i < totpoints - 1; i++) {
calchandle_profile(&bezt[i], &bezt[i - 1], &bezt[i + 1]);
}
calchandle_profile(&bezt[totpoints - 1], &bezt[totpoints - 2], NULL);
+ /* Copy the handle locations back to the control points. */
+ for (i = 0; i < totpoints; i++) {
+ profile->path[i].h1_loc[0] = bezt[i].vec[0][0];
+ profile->path[i].h1_loc[1] = bezt[i].vec[0][1];
+ profile->path[i].h2_loc[0] = bezt[i].vec[2][0];
+ profile->path[i].h2_loc[1] = bezt[i].vec[2][1];
+ }
+
/* Create a list of edge indices with the most curved at the start, least curved at the end. */
curve_sorted = MEM_callocN(sizeof(CurvatureSortPoint) * totedges, "curve sorted");
for (i = 0; i < totedges; i++) {
@@ -718,7 +837,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
BLI_assert(j < n_segments);
}
- /* Do the sampling from bezier points, X values first, then Y values. */
+ /* Sample from the bezier points. X then Y values. */
BKE_curve_forward_diff_bezier(bezt[i].vec[1][0],
bezt[i].vec[2][0],
bezt[i + 1].vec[0][0],
@@ -738,7 +857,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
BLI_assert(i_sample <= n_segments);
}
-#ifdef DEBUG_profile_TABLE
+#ifdef DEBUG_PROFILE_TABLE
printf("CURVEPROFILE CREATE SAMPLES\n");
printf("n_segments: %d\n", n_segments);
printf("totedges: %d\n", totedges);
@@ -755,6 +874,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
}
printf("\n");
#endif
+
MEM_freeN(bezt);
MEM_freeN(curve_sorted);
MEM_freeN(n_samples);
@@ -825,8 +945,10 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile)
profile->path[0].x = 1.0f;
profile->path[0].y = 0.0f;
+ profile->path[0].profile = profile;
profile->path[1].x = 1.0f;
profile->path[1].y = 1.0f;
+ profile->path[1].profile = profile;
profile->changed_timestamp = 0;
}
@@ -850,13 +972,14 @@ struct CurveProfile *BKE_curveprofile_add(int preset)
/**
* Should be called after the widget is changed. Does profile and remove double checks and more
* importantly, recreates the display / evaluation and segments tables.
+ * \param update_flags: Bitfield with fields defined in header file. Controls removing doubles and
+ * clipping.
*/
-void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double)
+void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
{
CurveProfilePoint *points = profile->path;
rctf *clipr = &profile->clip_rect;
float thresh;
- float dx, dy;
int i;
profile->changed_timestamp++;
@@ -864,11 +987,16 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double)
/* Clamp with the clipping rect in case something got past. */
if (profile->flag & PROF_USE_CLIP) {
/* Move points inside the clip rectangle. */
- for (i = 0; i < profile->path_len; i++) {
- points[i].x = max_ff(points[i].x, clipr->xmin);
- points[i].x = min_ff(points[i].x, clipr->xmax);
- points[i].y = max_ff(points[i].y, clipr->ymin);
- points[i].y = min_ff(points[i].y, clipr->ymax);
+ if (update_flags & PROF_UPDATE_CLIP) {
+ for (i = 0; i < profile->path_len; i++) {
+ points[i].x = max_ff(points[i].x, clipr->xmin);
+ points[i].x = min_ff(points[i].x, clipr->xmax);
+ points[i].y = max_ff(points[i].y, clipr->ymin);
+ points[i].y = min_ff(points[i].y, clipr->ymax);
+
+ /* Extra sanity assert to make sure the points have the right profile pointer. */
+ BLI_assert(points[i].profile == profile);
+ }
}
/* Ensure zoom-level respects clipping. */
if (BLI_rctf_size_x(&profile->view_rect) > BLI_rctf_size_x(&profile->clip_rect)) {
@@ -882,30 +1010,19 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double)
}
/* Remove doubles with a threshold set at 1% of default range. */
- thresh = 0.01f * BLI_rctf_size_x(clipr);
- if (remove_double && profile->path_len > 2) {
+ thresh = pow2f(0.01f * BLI_rctf_size_x(clipr));
+ if (update_flags & PROF_UPDATE_REMOVE_DOUBLES && profile->path_len > 2) {
for (i = 0; i < profile->path_len - 1; i++) {
- dx = points[i].x - points[i + 1].x;
- dy = points[i].y - points[i + 1].y;
- if (sqrtf(dx * dx + dy * dy) < thresh) {
+ if (len_squared_v2v2(&points[i].x, &points[i + 1].x) < thresh) {
if (i == 0) {
- points[i + 1].flag |= HD_VECT;
- if (points[i + 1].flag & PROF_SELECT) {
- points[i].flag |= PROF_SELECT;
- }
+ BKE_curveprofile_remove_point(profile, &points[1]);
}
else {
- points[i].flag |= HD_VECT;
- if (points[i].flag & PROF_SELECT) {
- points[i + 1].flag |= PROF_SELECT;
- }
+ BKE_curveprofile_remove_point(profile, &points[i]);
}
- break; /* Assumes 1 deletion per edit is ok. */
+ break; /* Assumes 1 deletion per update call is ok. */
}
}
- if (i != profile->path_len - 1) {
- BKE_curveprofile_remove_by_flag(profile, 2);
- }
}
/* Create the high resolution table for drawing and some evaluation functions. */
@@ -925,10 +1042,13 @@ void BKE_curveprofile_update(CurveProfile *profile, const bool remove_double)
*/
void BKE_curveprofile_initialize(CurveProfile *profile, short segments_len)
{
+ if (segments_len != profile->segments_len) {
+ profile->flag |= PROF_DIRTY_PRESET;
+ }
profile->segments_len = segments_len;
/* Calculate the higher resolution / segments tables for display and evaluation. */
- BKE_curveprofile_update(profile, false);
+ BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
}
/**
@@ -1070,3 +1190,22 @@ void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
*x_out = interpf(profile->table[i].x, profile->table[i + 1].x, lerp_factor);
*y_out = interpf(profile->table[i].y, profile->table[i + 1].y, lerp_factor);
}
+
+void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile)
+{
+ BLO_write_struct(writer, CurveProfile, profile);
+ BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path);
+}
+
+/* Expects that the curve profile itself has been read already. */
+void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
+{
+ BLO_read_data_address(reader, &profile->path);
+ profile->table = NULL;
+ profile->segments = NULL;
+
+ /* Reset the points' pointers to the profile. */
+ for (int i = 0; i < profile->path_len; i++) {
+ profile->path[i].profile = profile;
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 7dd4d1178ef..2be61239ac6 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -858,7 +858,6 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
if (m->a < min->a) {
min->a = m->a;
}
-
if (m->r > max->r) {
max->r = m->r;
}
@@ -1355,7 +1354,7 @@ static void layerCopyValue_propcol(const void *source,
/* Modes that do a full copy or nothing. */
if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
/* TODO: Check for a real valid way to get 'factor' value of our dest color? */
- const float f = (m2->col[0] + m2->col[1] + m2->col[2]) / 3.0f;
+ const float f = (m2->color[0] + m2->color[1] + m2->color[2]) / 3.0f;
if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
return; /* Do Nothing! */
}
@@ -1363,29 +1362,29 @@ static void layerCopyValue_propcol(const void *source,
return; /* Do Nothing! */
}
}
- copy_v3_v3(m2->col, m1->col);
+ copy_v3_v3(m2->color, m1->color);
}
else { /* Modes that support 'real' mix factor. */
if (mixmode == CDT_MIX_MIX) {
- blend_color_mix_float(tmp_col, m2->col, m1->col);
+ blend_color_mix_float(tmp_col, m2->color, m1->color);
}
else if (mixmode == CDT_MIX_ADD) {
- blend_color_add_float(tmp_col, m2->col, m1->col);
+ blend_color_add_float(tmp_col, m2->color, m1->color);
}
else if (mixmode == CDT_MIX_SUB) {
- blend_color_sub_float(tmp_col, m2->col, m1->col);
+ blend_color_sub_float(tmp_col, m2->color, m1->color);
}
else if (mixmode == CDT_MIX_MUL) {
- blend_color_mul_float(tmp_col, m2->col, m1->col);
+ blend_color_mul_float(tmp_col, m2->color, m1->color);
}
else {
- memcpy(tmp_col, m1->col, sizeof(tmp_col));
+ memcpy(tmp_col, m1->color, sizeof(tmp_col));
}
- blend_color_interpolate_float(m2->col, m2->col, tmp_col, mixfactor);
+ blend_color_interpolate_float(m2->color, m2->color, tmp_col, mixfactor);
- copy_v3_v3(m2->col, m1->col);
+ copy_v3_v3(m2->color, m1->color);
}
- m2->col[3] = m1->col[3];
+ m2->color[3] = m1->color[3];
}
static bool layerEqual_propcol(const void *data1, const void *data2)
@@ -1394,7 +1393,7 @@ static bool layerEqual_propcol(const void *data1, const void *data2)
float tot = 0;
for (int i = 0; i < 4; i++) {
- float c = (m1->col[i] - m2->col[i]);
+ float c = (m1->color[i] - m2->color[i]);
tot += c * c;
}
@@ -1404,29 +1403,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2)
static void layerMultiply_propcol(void *data, float fac)
{
MPropCol *m = data;
- mul_v4_fl(m->col, fac);
+ mul_v4_fl(m->color, fac);
}
static void layerAdd_propcol(void *data1, const void *data2)
{
MPropCol *m = data1;
const MPropCol *m2 = data2;
- add_v4_v4(m->col, m2->col);
+ add_v4_v4(m->color, m2->color);
}
static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
{
const MPropCol *m = data;
MPropCol *min = vmin, *max = vmax;
- minmax_v4v4_v4(min->col, max->col, m->col);
+ minmax_v4v4_v4(min->color, max->color, m->color);
}
static void layerInitMinMax_propcol(void *vmin, void *vmax)
{
MPropCol *min = vmin, *max = vmax;
- copy_v4_fl(min->col, FLT_MAX);
- copy_v4_fl(max->col, FLT_MIN);
+ copy_v4_fl(min->color, FLT_MAX);
+ copy_v4_fl(max->color, FLT_MIN);
}
static void layerDefault_propcol(void *data, int count)
@@ -1436,7 +1435,7 @@ static void layerDefault_propcol(void *data, int count)
MPropCol *pcol = (MPropCol *)data;
int i;
for (i = 0; i < count; i++) {
- copy_v4_v4(pcol[i].col, default_propcol.col);
+ copy_v4_v4(pcol[i].color, default_propcol.color);
}
}
@@ -1450,14 +1449,14 @@ static void layerInterp_propcol(
float weight = weights ? weights[i] : 1.0f;
const MPropCol *src = sources[i];
if (sub_weights) {
- madd_v4_v4fl(col, src->col, (*sub_weight) * weight);
+ madd_v4_v4fl(col, src->color, (*sub_weight) * weight);
sub_weight++;
}
else {
- madd_v4_v4fl(col, src->col, weight);
+ madd_v4_v4fl(col, src->color, weight);
}
}
- copy_v4_v4(mc->col, col);
+ copy_v4_v4(mc->color, col);
}
static int layerMaxNum_propcol(void)
@@ -1784,7 +1783,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(MPropCol),
"MPropCol",
1,
- N_("Col"),
+ N_("Color"),
NULL,
NULL,
layerInterp_propcol,
@@ -1871,7 +1870,7 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
};
const CustomData_MeshMasks CD_MASK_MESH = {
.vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_GENERIC_DATA),
+ CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = 0,
.lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
@@ -1881,7 +1880,7 @@ const CustomData_MeshMasks CD_MASK_MESH = {
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_GENERIC_DATA),
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_GENERIC_DATA),
.fmask = 0,
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
@@ -1890,7 +1889,7 @@ const CustomData_MeshMasks CD_MASK_EDITMESH = {
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
.vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
- CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA),
+ CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
.lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
@@ -1901,7 +1900,8 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
};
const CustomData_MeshMasks CD_MASK_BMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA),
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA |
+ CD_MASK_PROP_COLOR),
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = 0,
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
@@ -1925,7 +1925,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
.vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
- CD_MASK_GENERIC_DATA),
+ CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT |
CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
diff --git a/source/blender/blenkernel/intern/derived_node_tree.cc b/source/blender/blenkernel/intern/derived_node_tree.cc
index 961fef958b7..b53457812ba 100644
--- a/source/blender/blenkernel/intern/derived_node_tree.cc
+++ b/source/blender/blenkernel/intern/derived_node_tree.cc
@@ -20,12 +20,13 @@
#define UNINITIALIZED_ID UINT32_MAX
-namespace BKE {
+namespace blender {
+namespace bke {
static const NodeTreeRef &get_tree_ref(NodeTreeRefMap &node_tree_refs, bNodeTree *btree)
{
- return *node_tree_refs.lookup_or_add_cb(
- btree, [&]() { return blender::make_unique<NodeTreeRef>(btree); });
+ return *node_tree_refs.lookup_or_add_cb(btree,
+ [&]() { return std::make_unique<NodeTreeRef>(btree); });
}
DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : m_btree(btree)
@@ -173,7 +174,7 @@ BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_
Span<DNode *> nodes_by_id,
DNode &group_node)
{
- Span<const NodeRef *> node_refs = group_ref.nodes_with_idname("NodeGroupInput");
+ Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput");
if (node_refs.size() == 0) {
return;
}
@@ -220,7 +221,7 @@ BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group
Span<DNode *> nodes_by_id,
DNode &group_node)
{
- Span<const NodeRef *> node_refs = group_ref.nodes_with_idname("NodeGroupOutput");
+ Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput");
if (node_refs.size() == 0) {
return;
}
@@ -320,7 +321,8 @@ BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids(
DNode *node = m_nodes_by_id[node_index];
node->m_id = node_index;
- m_nodes_by_idname.lookup_or_add_default(node->idname()).append(node);
+ const bNodeType *nodetype = node->m_node_ref->bnode()->typeinfo;
+ m_nodes_by_type.lookup_or_add_default(nodetype).append(node);
for (DInputSocket *socket : node->m_inputs) {
socket->m_id = m_sockets_by_id.append_and_get_index(socket);
@@ -356,19 +358,17 @@ DerivedNodeTree::~DerivedNodeTree()
}
}
-namespace Dot = blender::DotExport;
-
-static Dot::Cluster *get_cluster_for_parent(Dot::DirectedGraph &graph,
- Map<const DParentNode *, Dot::Cluster *> &clusters,
+static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph,
+ Map<const DParentNode *, dot::Cluster *> &clusters,
const DParentNode *parent)
{
if (parent == nullptr) {
return nullptr;
}
return clusters.lookup_or_add_cb(parent, [&]() {
- Dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent());
+ dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent());
bNodeTree *btree = (bNodeTree *)parent->node_ref().bnode()->id;
- Dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " +
+ dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " +
StringRef(btree->id.name + 2));
new_cluster->set_parent_cluster(parent_cluster);
return new_cluster;
@@ -377,15 +377,15 @@ static Dot::Cluster *get_cluster_for_parent(Dot::DirectedGraph &graph,
std::string DerivedNodeTree::to_dot() const
{
- Dot::DirectedGraph digraph;
- digraph.set_rankdir(Dot::Attr_rankdir::LeftToRight);
+ dot::DirectedGraph digraph;
+ digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
- Map<const DNode *, Dot::NodeWithSocketsRef> dot_nodes;
- Map<const DGroupInput *, Dot::NodeWithSocketsRef> dot_group_inputs;
- Map<const DParentNode *, Dot::Cluster *> dot_clusters;
+ Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes;
+ Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs;
+ Map<const DParentNode *, dot::Cluster *> dot_clusters;
for (const DNode *node : m_nodes_by_id) {
- Dot::Node &dot_node = digraph.new_node("");
+ dot::Node &dot_node = digraph.new_node("");
dot_node.set_background_color("white");
Vector<std::string> input_names;
@@ -398,37 +398,37 @@ std::string DerivedNodeTree::to_dot() const
}
dot_nodes.add_new(node,
- Dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
+ dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
- Dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent());
+ dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent());
dot_node.set_parent_cluster(cluster);
}
for (const DGroupInput *group_input : m_group_inputs) {
- Dot::Node &dot_node = digraph.new_node("");
+ dot::Node &dot_node = digraph.new_node("");
dot_node.set_background_color("white");
std::string group_input_name = group_input->name();
dot_group_inputs.add_new(
- group_input, Dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name}));
+ group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name}));
- Dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent());
+ dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent());
dot_node.set_parent_cluster(cluster);
}
for (const DNode *to_node : m_nodes_by_id) {
- Dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node);
+ dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node);
for (const DInputSocket *to_socket : to_node->inputs()) {
for (const DOutputSocket *from_socket : to_socket->linked_sockets()) {
const DNode *from_node = &from_socket->node();
- Dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node);
+ dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node);
digraph.new_edge(from_dot_node.output(from_socket->index()),
to_dot_node.input(to_socket->index()));
}
for (const DGroupInput *group_input : to_socket->linked_group_inputs()) {
- Dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input);
+ dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input);
digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index()));
}
@@ -439,4 +439,5 @@ std::string DerivedNodeTree::to_dot() const
return digraph.to_dot_string();
}
-} // namespace BKE
+} // namespace bke
+} // namespace blender
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index dae8a59fe43..2e1fa519284 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -5112,7 +5112,7 @@ static void dynamic_paint_prepare_effect_cb(void *__restrict userdata,
EffectedPoint epoint;
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
epoint.vel_to_sec = 1.0f;
- BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL, NULL);
}
/* if global gravity is enabled, add it too */
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 3d5f9cad1c1..1a5b7685c0e 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -237,12 +237,13 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
{
BMesh *bm = em->bm;
- /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
- * Similar code to MESH_OT_customdata_custom_splitnormals_add operator,
- * we want to keep same shading in case we were using autosmooth so far.
+ /* We need to create custom-loop-normals (CLNORS) data if none exist yet,
+ * otherwise there is no way to edit them.
+ * Similar code to #MESH_OT_customdata_custom_splitnormals_add operator,
+ * we want to keep same shading in case we were using auto-smooth so far.
* Note: there is a problem here, which is that if someone starts a normal editing operation on
- * previously autosmooth-ed mesh, and cancel that operation, generated clnors data remain,
- * with related sharp edges (and hence autosmooth is 'lost').
+ * previously auto-smooth-ed mesh, and cancel that operation, generated CLNORS data remain,
+ * with related sharp edges (and hence auto-smooth is 'lost').
* Not sure how critical this is, and how to fix that issue? */
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
if (me->flag & ME_AUTOSMOOTH) {
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index fe2c9ed51b8..235c834fde9 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -108,7 +108,8 @@ PartDeflect *BKE_partdeflect_new(int type)
break;
case PFIELD_WIND:
pd->shape = PFIELD_SHAPE_PLANE;
- pd->f_flow = 1.0f; /* realistic wind behavior */
+ pd->f_flow = 1.0f; /* realistic wind behavior */
+ pd->f_wind_factor = 1.0f; /* only act perpendicularly to a surface */
break;
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
@@ -428,7 +429,7 @@ static float eff_calc_visibility(ListBase *colliders,
EffectorData *efd,
EffectedPoint *point)
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
ListBase *colls = colliders;
ColliderCache *col;
float norm[3], len = 0.0;
@@ -1072,7 +1073,8 @@ static void do_physical_effector(EffectorCache *eff,
* scene = scene where it runs in, for time and stuff
* lb = listbase with objects that take part in effecting
* opco = global coord, as input
- * force = force accumulator
+ * force = accumulator for force
+ * wind_force = accumulator for force only acting perpendicular to a surface
* speed = actual current speed which can be altered
* cur_time = "external" time in frames, is constant for static particles
* loc_time = "local" time in frames, range <0-1> for the lifetime of particle
@@ -1085,6 +1087,7 @@ void BKE_effectors_apply(ListBase *effectors,
EffectorWeights *weights,
EffectedPoint *point,
float *force,
+ float *wind_force,
float *impulse)
{
/*
@@ -1120,22 +1123,27 @@ void BKE_effectors_apply(ListBase *effectors,
if (efd.falloff > 0.0f) {
efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point);
}
- if (efd.falloff <= 0.0f) {
- /* don't do anything */
- }
- else if (eff->pd->forcefield == PFIELD_TEXTURE) {
- do_texture_effector(eff, &efd, point, force);
- }
- else {
- float temp1[3] = {0, 0, 0}, temp2[3];
- copy_v3_v3(temp1, force);
+ if (efd.falloff > 0.0f) {
+ float out_force[3] = {0, 0, 0};
- do_physical_effector(eff, &efd, point, force);
+ if (eff->pd->forcefield == PFIELD_TEXTURE) {
+ do_texture_effector(eff, &efd, point, out_force);
+ }
+ else {
+ do_physical_effector(eff, &efd, point, out_force);
- /* for softbody backward compatibility */
- if (point->flag & PE_WIND_AS_SPEED && impulse) {
- sub_v3_v3v3(temp2, force, temp1);
- sub_v3_v3v3(impulse, impulse, temp2);
+ /* for softbody backward compatibility */
+ if (point->flag & PE_WIND_AS_SPEED && impulse) {
+ sub_v3_v3v3(impulse, impulse, out_force);
+ }
+ }
+
+ if (wind_force) {
+ madd_v3_v3fl(force, out_force, 1.0f - eff->pd->f_wind_factor);
+ madd_v3_v3fl(wind_force, out_force, eff->pd->f_wind_factor);
+ }
+ else {
+ add_v3_v3(force, out_force);
}
}
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index d4754615c7f..bc14f525c2c 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1063,9 +1063,9 @@ static BezTriple *cycle_offset_triple(
/**
* Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
*
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually `SELECT`, but may want to use a different one at times
+ * (if caller does not operate on selection).
*/
void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 78a6cf28824..a0625918a62 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -484,14 +484,14 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
dtar->flag &= ~DTAR_FLAG_INVALID;
}
- /* try to get posechannel */
+ /* Try to get pose-channel. */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
- /* check if object or bone, and get transform matrix accordingly
- * - "useEulers" code is used to prevent the problems associated with non-uniqueness
- * of euler decomposition from matrices [#20870]
- * - localspace is for [#21384], where parent results are not wanted
- * but local-consts is for all the common "corrective-shapes-for-limbs" situations
+ /* Check if object or bone, and get transform matrix accordingly:
+ * - "use_eulers" code is used to prevent the problems associated with non-uniqueness
+ * of euler decomposition from matrices T20870.
+ * - "local-space" is for T21384, where parent results are not wanted
+ * but #DTAR_FLAG_LOCAL_CONSTS is for all the common "corrective-shapes-for-limbs" situations.
*/
if (pchan) {
/* bone */
@@ -517,7 +517,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
}
else {
- /* worldspace matrix */
+ /* World-space matrix. */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index b75592836e0..98573ea98ec 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -3175,7 +3175,8 @@ static void update_effectors_task_cb(void *__restrict userdata,
/* do effectors */
pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint);
- BKE_effectors_apply(data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL);
+ BKE_effectors_apply(
+ data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL, NULL);
/* convert retvel to local space */
mag = len_v3(retvel);
@@ -3793,8 +3794,8 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
int next_frame = scene_framenr + 1;
int prev_frame = scene_framenr - 1;
- /* Ensure positivity of previous frame. */
- CLAMP(prev_frame, mds->cache_frame_start, prev_frame);
+ /* Ensure positive of previous frame. */
+ CLAMP_MIN(prev_frame, mds->cache_frame_start);
int data_frame = scene_framenr, noise_frame = scene_framenr;
int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
@@ -3808,6 +3809,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+ bool with_resumable_cache = mds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE;
bool with_script, with_adaptive, with_noise, with_mesh, with_particles, with_guide;
with_script = mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT;
with_adaptive = mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN;
@@ -3867,13 +3869,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Cache mode specific settings. */
switch (mode) {
- case FLUID_DOMAIN_CACHE_FINAL:
- /* Just load the data that has already been baked */
- if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
- read_cache = true;
- bake_cache = false;
- }
- break;
+ case FLUID_DOMAIN_CACHE_ALL:
case FLUID_DOMAIN_CACHE_MODULAR:
/* Just load the data that has already been baked */
if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
@@ -3901,10 +3897,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
/* Noise, mesh and particles can never be baked more than data. */
- CLAMP(noise_frame, noise_frame, data_frame);
- CLAMP(mesh_frame, mesh_frame, data_frame);
- CLAMP(particles_frame, particles_frame, data_frame);
- CLAMP(guide_frame, guide_frame, mds->cache_frame_end);
+ CLAMP_MAX(noise_frame, data_frame);
+ CLAMP_MAX(mesh_frame, data_frame);
+ CLAMP_MAX(particles_frame, data_frame);
+ CLAMP_MAX(guide_frame, mds->cache_frame_end);
/* Force to read cache as we're resuming the bake */
read_cache = true;
@@ -3928,6 +3924,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
break;
}
+ bool read_partial = false, read_all = false;
/* Try to read from cache and keep track of read success. */
if (read_cache) {
@@ -3936,20 +3933,16 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
has_config = manta_read_config(mds->fluid, mmd, mesh_frame);
/* Update mesh data from file is faster than via Python (manta_read_mesh()). */
- has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame);
+ has_mesh = manta_read_mesh(mds->fluid, mmd, mesh_frame);
}
/* Read particles cache. */
if (with_liquid && with_particles) {
has_config = manta_read_config(mds->fluid, mmd, particles_frame);
- if (!baking_data && !baking_particles && next_particles) {
- /* Update particle data from file is faster than via Python (manta_read_particles()). */
- has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame);
- }
- else {
- has_particles = manta_read_particles(mds->fluid, mmd, particles_frame);
- }
+ read_partial = !baking_data && !baking_particles && next_particles;
+ read_all = !read_partial && with_resumable_cache;
+ has_particles = manta_read_particles(mds->fluid, mmd, particles_frame, read_all);
}
/* Read guide cache. */
@@ -3967,12 +3960,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
- if (!baking_data && !baking_noise && next_noise) {
- has_noise = manta_update_noise_structures(mds->fluid, mmd, noise_frame);
- }
- else {
- has_noise = manta_read_noise(mds->fluid, mmd, noise_frame);
- }
+
+ read_partial = !baking_data && !baking_noise && next_noise;
+ read_all = !read_partial && with_resumable_cache;
+ has_noise = manta_read_noise(mds->fluid, mmd, noise_frame, read_all);
/* When using the adaptive domain, copy all data that was read to a new fluid object. */
if (with_adaptive && baking_noise) {
@@ -3986,12 +3977,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift);
}
}
- if (!baking_data && !baking_noise && next_data && next_noise) {
- /* Nothing to do here since we already loaded noise grids. */
- }
- else {
- has_data = manta_read_data(mds->fluid, mmd, data_frame);
- }
+
+ read_partial = !baking_data && !baking_noise && next_data && next_noise;
+ read_all = !read_partial && with_resumable_cache;
+ has_data = manta_read_data(mds->fluid, mmd, data_frame, read_all);
}
/* Read data cache only */
else {
@@ -4002,28 +3991,17 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
if (has_config && manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
- /* Read data cache */
- if (!baking_data && !baking_particles && !baking_mesh && next_data) {
- has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame);
- }
- else {
- has_data = manta_read_data(mds->fluid, mmd, data_frame);
- }
- }
- if (with_liquid) {
- if (!baking_data && !baking_particles && !baking_mesh && next_data) {
- has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame);
- }
- else {
- has_data = manta_read_data(mds->fluid, mmd, data_frame);
- }
}
+
+ read_partial = !baking_data && !baking_particles && !baking_mesh && next_data;
+ read_all = !read_partial && with_resumable_cache;
+ has_data = manta_read_data(mds->fluid, mmd, data_frame, read_all);
}
}
/* Cache mode specific settings */
switch (mode) {
- case FLUID_DOMAIN_CACHE_FINAL:
+ case FLUID_DOMAIN_CACHE_ALL:
case FLUID_DOMAIN_CACHE_MODULAR:
if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
bake_cache = false;
@@ -4605,13 +4583,9 @@ void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clea
void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, int type)
{
- /* Set common values for liquid/smoke domain: cache type,
- * border collision and viewport draw-type. */
+ /* Set values for border collision:
+ * Liquids should have a closed domain, smoke domains should be open. */
if (type == FLUID_DOMAIN_TYPE_GAS) {
- BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT);
- BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI);
- BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI);
- BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 1);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 1);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 1);
@@ -4621,10 +4595,6 @@ void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, in
object->dt = OB_WIRE;
}
else if (type == FLUID_DOMAIN_TYPE_LIQUID) {
- BKE_fluid_cachetype_mesh_set(settings, FLUID_DOMAIN_FILE_BIN_OBJECT);
- BKE_fluid_cachetype_data_set(settings, FLUID_DOMAIN_FILE_UNI);
- BKE_fluid_cachetype_particle_set(settings, FLUID_DOMAIN_FILE_UNI);
- BKE_fluid_cachetype_noise_set(settings, FLUID_DOMAIN_FILE_UNI);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_FRONT, 0);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BACK, 0);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_RIGHT, 0);
@@ -4986,12 +4956,12 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
/* OpenVDB cache options */
#ifdef WITH_OPENVDB_BLOSC
- mmd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+ mmd->domain->openvdb_compression = VDB_COMPRESSION_BLOSC;
#else
- mmd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+ mmd->domain->openvdb_compression = VDB_COMPRESSION_ZIP;
#endif
mmd->domain->clipping = 1e-6f;
- mmd->domain->data_depth = 0;
+ mmd->domain->openvdb_data_depth = 0;
}
else if (mmd->type & MOD_FLUID_TYPE_FLOW) {
if (mmd->flow) {
@@ -5228,9 +5198,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
}
/* OpenVDB cache options */
- tmds->openvdb_comp = mds->openvdb_comp;
+ tmds->openvdb_compression = mds->openvdb_compression;
tmds->clipping = mds->clipping;
- tmds->data_depth = mds->data_depth;
+ tmds->openvdb_data_depth = mds->openvdb_data_depth;
}
else if (tmmd->flow) {
FluidFlowSettings *tmfs = tmmd->flow;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 5771eb053f7..dfa5ff6975f 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -78,7 +78,7 @@ static void vfont_init_data(ID *id)
if (vfd) {
vfont->data = vfd;
- BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name));
+ BLI_strncpy(vfont->filepath, FO_BUILTIN_NAME, sizeof(vfont->filepath));
}
/* Free the packed file */
@@ -177,7 +177,7 @@ static int builtin_font_size = 0;
bool BKE_vfont_is_builtin(struct VFont *vfont)
{
- return STREQ(vfont->name, FO_BUILTIN_NAME);
+ return STREQ(vfont->filepath, FO_BUILTIN_NAME);
}
void BKE_vfont_builtin_register(void *mem, int size)
@@ -237,20 +237,20 @@ static VFontData *vfont_get_data(VFont *vfont)
}
}
else {
- pf = BKE_packedfile_new(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
+ pf = BKE_packedfile_new(NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
if (vfont->temp_pf == NULL) {
vfont->temp_pf = BKE_packedfile_new(
- NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
+ NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
}
}
if (!pf) {
- CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->name);
+ CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->filepath);
/* DON'T DO THIS
* missing file shouldn't modify path! - campbell */
#if 0
- strcpy(vfont->name, FO_BUILTIN_NAME);
+ strcpy(vfont->filepath, FO_BUILTIN_NAME);
#endif
pf = get_builtin_packedfile();
}
@@ -301,7 +301,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
if (vfd->name[0] != '\0') {
BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2);
}
- BLI_strncpy(vfont->name, filepath, sizeof(vfont->name));
+ BLI_strncpy(vfont->filepath, filepath, sizeof(vfont->filepath));
/* if autopack is on store the packedfile in de font structure */
if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
@@ -333,7 +333,7 @@ VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *
/* first search an identical filepath */
for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
- BLI_strncpy(strtest, vfont->name, sizeof(vfont->name));
+ BLI_strncpy(strtest, vfont->filepath, sizeof(vfont->filepath));
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
if (BLI_path_cmp(strtest, str) == 0) {
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index b460e6d6dc0..dece833c00f 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -289,6 +289,16 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
MEM_freeN(gpd_eval);
}
+/**
+ * Tag data-block for depsgraph update.
+ * Wrapper to avoid include Depsgraph tag functions in other modules.
+ * \param gpd: Grease pencil data-block.
+ */
+void BKE_gpencil_tag(bGPdata *gpd)
+{
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+}
+
/* ************************************************** */
/* Container Creation */
@@ -417,7 +427,7 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
gpl_active = BKE_gpencil_layer_active_get(gpd);
- /* add to datablock */
+ /* Add to data-block. */
if (gpl_active == NULL) {
BLI_addtail(&gpd->layers, gpl);
}
@@ -469,7 +479,9 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
return gpl;
}
-/* add a new gp-datablock */
+/**
+ * Add a new grease pencil data-block.
+ */
bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
bGPdata *gpd;
@@ -496,7 +508,7 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
- /* onion-skinning settings (datablock level) */
+ /* Onion-skinning settings (data-block level) */
gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
gpd->onion_flag |= GP_ONION_FADE;
gpd->onion_mode = GP_ONION_MODE_RELATIVE;
@@ -516,8 +528,8 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
/**
* Populate stroke with point data from data buffers
*
- * \param array: Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
- * \param mat: 4x4 transform matrix to transform points into the right coordinate space
+ * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
+ * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
*/
void BKE_gpencil_stroke_add_points(bGPDstroke *gps,
const float *array,
@@ -728,7 +740,9 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
return gpl_dst;
}
-/* Standard API to make a copy of GP datablock, separate from copying its data */
+/**
+ * Standard API to make a copy of GP data-block, separate from copying its data.
+ */
bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
{
bGPdata *gpd_copy;
@@ -736,8 +750,11 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
return gpd_copy;
}
-/* make a copy of a given gpencil datablock */
-/* XXX: Should this be deprecated? */
+/**
+ * Make a copy of a given gpencil data-block.
+ *
+ * XXX: Should this be deprecated?
+ */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -1319,7 +1336,7 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
/**
* Creates a new gpencil material and assigns it to object.
*
- * \param *r_index: value is set to zero based index of the new material if r_index is not NULL
+ * \param *r_index: value is set to zero based index of the new material if \a r_index is not NULL.
*/
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
@@ -1491,9 +1508,9 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
* Get range of selected frames in layer.
* Always the active frame is considered as selected, so if no more selected the range
* will be equal to the current active frame.
- * \param gpl: Layer
- * \param r_initframe: Number of first selected frame
- * \param r_endframe: Number of last selected frame
+ * \param gpl: Layer.
+ * \param r_initframe: Number of first selected frame.
+ * \param r_endframe: Number of last selected frame.
*/
void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
{
@@ -1514,11 +1531,11 @@ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_e
/**
* Get Falloff factor base on frame range
- * \param gpf: Frame
- * \param actnum: Number of active frame in layer
- * \param f_init: Number of first selected frame
- * \param f_end: Number of last selected frame
- * \param cur_falloff: Curve with falloff factors
+ * \param gpf: Frame.
+ * \param actnum: Number of active frame in layer.
+ * \param f_init: Number of first selected frame.
+ * \param f_end: Number of last selected frame.
+ * \param cur_falloff: Curve with falloff factors.
*/
float BKE_gpencil_multiframe_falloff_calc(
bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
@@ -1803,7 +1820,7 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size,
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
- if (ibuf->rect) {
+ if (ibuf && ibuf->rect) {
int img_x = ibuf->x;
int img_y = ibuf->y;
@@ -1848,10 +1865,10 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size,
/**
* Helper to check if a layers is used as mask
- * \param view_layer Actual view layer
- * \param gpd Grease pencil datablock
- * \param gpl_mask Actual Layer
- * \return True if the layer is used as mask
+ * \param view_layer: Actual view layer.
+ * \param gpd: Grease pencil data-block.
+ * \param gpl_mask: Actual Layer.
+ * \return True if the layer is used as mask.
*/
static bool gpencil_is_layer_mask(ViewLayer *view_layer, bGPdata *gpd, bGPDlayer *gpl_mask)
{
@@ -1874,8 +1891,7 @@ static bool gpencil_is_layer_mask(ViewLayer *view_layer, bGPdata *gpd, bGPDlayer
/** \name Iterators
*
* Iterate over all visible stroke of all visible layers inside a gpObject.
- * Also take into account onion skining.
- *
+ * Also take into account onion-skinning.
* \{ */
void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
@@ -2081,7 +2097,7 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev
/* Assign pointers to the original stroke and points to the evaluated data. This must
* be done before applying any modifier because at this moment the structure is equals,
- * so we can assume the layer index is the same in both datablocks.
+ * so we can assume the layer index is the same in both data-blocks.
* This data will be used by operators. */
bGPDlayer *gpl_eval = gpd_eval->layers.first;
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 8299943cc49..66e9e2184c1 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -386,7 +386,8 @@ static void gpencil_convert_spline(Main *bmain,
BKE_gpencil_stroke_geometry_update(gps);
}
-/* Convert a curve object to grease pencil stroke.
+/**
+ * Convert a curve object to grease pencil stroke.
*
* \param bmain: Main thread pointer
* \param scene: Original scene.
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index d200e4e3a15..542f80aa9b5 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -32,15 +32,22 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
+#include "BLT_translation.h"
+
#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -1244,7 +1251,8 @@ bool BKE_gpencil_stroke_trim(bGPDstroke *gps)
return false;
}
bool intersect = false;
- int start, end;
+ int start = 0;
+ int end = 0;
float point[3];
/* loop segments from start until we have an intersection */
for (int i = 0; i < gps->totpoints - 2; i++) {
@@ -1500,7 +1508,9 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta
}
/* Merge by distance ------------------------------------- */
-/* Reduce a series of points when the distance is below a threshold.
+
+/**
+ * Reduce a series of points when the distance is below a threshold.
* Special case for first and last points (both are keeped) for other points,
* the merge point always is at first point.
* \param gpf: Grease Pencil frame
@@ -1580,6 +1590,398 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
BKE_gpencil_stroke_geometry_update(gps);
}
+typedef struct GpEdge {
+ uint v1, v2;
+ /* Coordinates. */
+ float v1_co[3], v2_co[3];
+ /* Normals. */
+ float n1[3], n2[3];
+ /* Direction of the segment. */
+ float vec[3];
+ int flag;
+} GpEdge;
+
+static int gpencil_next_edge(
+ GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse)
+{
+ int edge = -1;
+ float last_angle = 999999.0f;
+ for (int i = 0; i < totedges; i++) {
+ GpEdge *gped = &gp_edges[i];
+ if (gped->flag != 0) {
+ continue;
+ }
+ if (reverse) {
+ if (gped_init->v1 != gped->v2) {
+ continue;
+ }
+ }
+ else {
+ if (gped_init->v2 != gped->v1) {
+ continue;
+ }
+ }
+ /* Look for straight lines. */
+ float angle = angle_v3v3(gped->vec, gped_init->vec);
+ if ((angle < threshold) && (angle <= last_angle)) {
+ edge = i;
+ last_angle = angle;
+ }
+ }
+
+ return edge;
+}
+
+static int gpencil_walk_edge(GHash *v_table,
+ GpEdge *gp_edges,
+ int totedges,
+ uint *stroke_array,
+ int init_idx,
+ const float angle,
+ const bool reverse)
+{
+ GpEdge *gped_init = &gp_edges[init_idx];
+ int idx = 1;
+ int edge = 0;
+ while (edge > -1) {
+ edge = gpencil_next_edge(gp_edges, totedges, gped_init, angle, reverse);
+ if (edge > -1) {
+ GpEdge *gped = &gp_edges[edge];
+ stroke_array[idx] = edge;
+ gped->flag = 1;
+ gped_init = &gp_edges[edge];
+ idx++;
+
+ /* Avoid to follow already visited vertice. */
+ if (reverse) {
+ if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v1))) {
+ edge = -1;
+ }
+ else {
+ BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v1), POINTER_FROM_INT(gped->v1));
+ }
+ }
+ else {
+ if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v2))) {
+ edge = -1;
+ }
+ else {
+ BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v2), POINTER_FROM_INT(gped->v2));
+ }
+ }
+ }
+ }
+
+ return idx;
+}
+
+static void gpencil_generate_edgeloops(Object *ob,
+ bGPDframe *gpf_stroke,
+ const float angle,
+ const int thickness,
+ const float offset,
+ const float matrix[4][4],
+ const bool use_seams)
+{
+ Mesh *me = (Mesh *)ob->data;
+ if (me->totedge == 0) {
+ return;
+ }
+
+ /* Arrays for all edge vertices (forward and backward) that form a edge loop.
+ * This is reused for each edgeloop to create gpencil stroke. */
+ uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__);
+ uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
+ uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
+
+ /* Create array with all edges. */
+ GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__);
+ GpEdge *gped = NULL;
+ for (int i = 0; i < me->totedge; i++) {
+ MEdge *ed = &me->medge[i];
+ gped = &gp_edges[i];
+ MVert *mv1 = &me->mvert[ed->v1];
+ normal_short_to_float_v3(gped->n1, mv1->no);
+
+ gped->v1 = ed->v1;
+ copy_v3_v3(gped->v1_co, mv1->co);
+
+ MVert *mv2 = &me->mvert[ed->v2];
+ normal_short_to_float_v3(gped->n2, mv2->no);
+ gped->v2 = ed->v2;
+ copy_v3_v3(gped->v2_co, mv2->co);
+
+ sub_v3_v3v3(gped->vec, mv1->co, mv2->co);
+
+ /* If use seams, mark as done if not a seam. */
+ if ((use_seams) && ((ed->flag & ME_SEAM) == 0)) {
+ gped->flag = 1;
+ }
+ }
+
+ /* Loop edges to find edgeloops */
+ bool pending = true;
+ int e = 0;
+ while (pending) {
+ /* Clear arrays of stroke. */
+ memset(stroke_fw, 0, sizeof(uint) * me->totedge);
+ memset(stroke_bw, 0, sizeof(uint) * me->totedge);
+ memset(stroke, 0, sizeof(uint) * me->totedge * 2);
+
+ gped = &gp_edges[e];
+ /* Look first unused edge. */
+ if (gped->flag != 0) {
+ e++;
+ if (e == me->totedge) {
+ pending = false;
+ }
+ continue;
+ }
+ /* Add current edge to arrays. */
+ stroke_fw[0] = e;
+ stroke_bw[0] = e;
+ gped->flag = 1;
+
+ /* Hash used to avoid loop over same vertice. */
+ GHash *v_table = BLI_ghash_int_new(__func__);
+ /* Look forward edges. */
+ int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, angle, false);
+ /* Look backward edges. */
+ int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true);
+
+ BLI_ghash_free(v_table, NULL, NULL);
+
+ /* Join both arrays. */
+ int array_len = 0;
+ for (int i = totbw - 1; i > 0; i--) {
+ stroke[array_len] = stroke_bw[i];
+ array_len++;
+ }
+ for (int i = 0; i < totedges; i++) {
+ stroke[array_len] = stroke_fw[i];
+ array_len++;
+ }
+
+ /* Create Stroke. */
+ bGPDstroke *gps_stroke = BKE_gpencil_stroke_add(
+ gpf_stroke, 0, array_len + 1, thickness * thickness, false);
+
+ /* Create first segment. */
+ float fpt[3];
+ uint v = stroke[0];
+ gped = &gp_edges[v];
+ bGPDspoint *pt = &gps_stroke->points[0];
+ mul_v3_v3fl(fpt, gped->n1, offset);
+ add_v3_v3v3(&pt->x, gped->v1_co, fpt);
+ mul_m4_v3(matrix, &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+
+ pt = &gps_stroke->points[1];
+ mul_v3_v3fl(fpt, gped->n2, offset);
+ add_v3_v3v3(&pt->x, gped->v2_co, fpt);
+ mul_m4_v3(matrix, &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+
+ /* Add next segments. */
+ for (int i = 1; i < array_len; i++) {
+ v = stroke[i];
+ gped = &gp_edges[v];
+
+ pt = &gps_stroke->points[i + 1];
+ mul_v3_v3fl(fpt, gped->n2, offset);
+ add_v3_v3v3(&pt->x, gped->v2_co, fpt);
+ mul_m4_v3(matrix, &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ }
+
+ BKE_gpencil_stroke_geometry_update(gps_stroke);
+ }
+
+ /* Free memory. */
+ MEM_SAFE_FREE(stroke);
+ MEM_SAFE_FREE(stroke_fw);
+ MEM_SAFE_FREE(stroke_bw);
+ MEM_SAFE_FREE(gp_edges);
+}
+
+/* Helper: Add gpencil material using material as base. */
+static Material *gpencil_add_material(Main *bmain,
+ Object *ob_gp,
+ const char *name,
+ const float color[4],
+ const bool use_stroke,
+ const bool use_fill,
+ int *r_idx)
+{
+ Material *mat_gp = BKE_gpencil_object_material_new(bmain, ob_gp, name, r_idx);
+ MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+ /* Stroke color. */
+ if (use_stroke) {
+ ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+ else {
+ linearrgb_to_srgb_v4(gp_style->stroke_rgba, color);
+ gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ }
+
+ /* Fill color. */
+ linearrgb_to_srgb_v4(gp_style->fill_rgba, color);
+ if (use_fill) {
+ gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+
+ /* Check at least one is enabled. */
+ if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
+ ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+
+ return mat_gp;
+}
+
+/**
+ * Convert a mesh object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer.
+ * \param depsgraph: Original depsgraph.
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_mesh: Mesh to convert.
+ * \param angle: Limit angle to consider a edgeloop ends.
+ * \param thickness: Thickness of the strokes.
+ * \param offset: Offset along the normals.
+ * \param matrix: Transformation matrix.
+ * \param frame_offset: Destination frame number offset.
+ * \param use_seams: Only export seam edges.
+ * \param use_faces: Export faces as filled strokes.
+ */
+void BKE_gpencil_convert_mesh(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob_gp,
+ Object *ob_mesh,
+ const float angle,
+ const int thickness,
+ const float offset,
+ const float matrix[4][4],
+ const int frame_offset,
+ const bool use_seams,
+ const bool use_faces)
+{
+ if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ return;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob_gp->data;
+
+ /* Use evaluated data to get mesh with all modifiers on top. */
+ Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, ob_mesh);
+ Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
+ MPoly *mp, *mpoly = me_eval->mpoly;
+ MLoop *mloop = me_eval->mloop;
+ int mpoly_len = me_eval->totpoly;
+ int i;
+
+ /* If the object has enough materials means it was created in a previous step. */
+ const bool create_mat = ((ob_gp->totcol > 0) && (ob_gp->totcol >= ob_mesh->totcol)) ? false :
+ true;
+
+ /* Need at least an edge. */
+ if (me_eval->totvert < 2) {
+ return;
+ }
+
+ int r_idx;
+ const float default_colors[2][4] = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.7f, 0.7f, 0.7f, 1.0f}};
+ /* Create stroke material. */
+ if (create_mat) {
+ gpencil_add_material(bmain, ob_gp, "Stroke", default_colors[0], true, false, &r_idx);
+ }
+ /* Export faces as filled strokes. */
+ if (use_faces) {
+ if (create_mat) {
+ /* Find a material slot with material assigned */
+ bool material_found = false;
+ for (i = 0; i < ob_mesh->totcol; i++) {
+ Material *ma = BKE_object_material_get(ob_mesh, i + 1);
+ if (ma != NULL) {
+ material_found = true;
+ break;
+ }
+ }
+
+ /* If no materials, create a simple fill. */
+ if (!material_found) {
+ gpencil_add_material(bmain, ob_gp, "Fill", default_colors[1], false, true, &r_idx);
+ }
+ else {
+ /* Create all materials for fill. */
+ for (i = 0; i < ob_mesh->totcol; i++) {
+ Material *ma = BKE_object_material_get(ob_mesh, i + 1);
+ if (ma == NULL) {
+ continue;
+ }
+ float color[4];
+ copy_v3_v3(color, &ma->r);
+ color[3] = 1.0f;
+ gpencil_add_material(bmain, ob_gp, ma->id.name + 2, color, false, true, &r_idx);
+ }
+ }
+ }
+
+ /* Read all polygons and create fill for each. */
+ if (mpoly_len > 0) {
+ bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, DATA_("Fills"));
+ if (gpl_fill == NULL) {
+ gpl_fill = BKE_gpencil_layer_addnew(gpd, DATA_("Fills"), true);
+ }
+ bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(
+ gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW);
+ for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
+ MLoop *ml = &mloop[mp->loopstart];
+ /* Create fill stroke. */
+ bGPDstroke *gps_fill = BKE_gpencil_stroke_add(
+ gpf_fill, mp->mat_nr + 1, mp->totloop, 10, false);
+ gps_fill->flag |= GP_STROKE_CYCLIC;
+
+ /* Add points to strokes. */
+ int j;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ MVert *mv = &me_eval->mvert[ml->v];
+
+ bGPDspoint *pt = &gps_fill->points[j];
+ copy_v3_v3(&pt->x, mv->co);
+ mul_m4_v3(matrix, &pt->x);
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ }
+
+ BKE_gpencil_stroke_geometry_update(gps_fill);
+ }
+ }
+ }
+
+ /* Create stroke from edges. */
+ bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, DATA_("Lines"));
+ if (gpl_stroke == NULL) {
+ gpl_stroke = BKE_gpencil_layer_addnew(gpd, DATA_("Lines"), true);
+ }
+ bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get(
+ gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW);
+ gpencil_generate_edgeloops(ob_eval, gpf_stroke, angle, thickness, offset, matrix, use_seams);
+
+ /* Tag for recalculation */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
+
/* Apply Transforms */
void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 2f8500bd1df..fa0cbb0ab5c 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -53,6 +53,9 @@
#include "MOD_gpencil_modifiertypes.h"
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.gpencil_modifier"};
static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = {NULL};
/* *************************************************** */
@@ -275,8 +278,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps)
/* init lattice deform data */
void BKE_gpencil_lattice_init(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type == eGpencilModifierType_Lattice) {
LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
Object *latob = NULL;
@@ -298,8 +300,7 @@ void BKE_gpencil_lattice_init(Object *ob)
/* clear lattice deform data */
void BKE_gpencil_lattice_clear(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type == eGpencilModifierType_Lattice) {
LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
if ((mmd) && (mmd->cache_data)) {
@@ -316,8 +317,7 @@ void BKE_gpencil_lattice_clear(Object *ob)
/* check if exist geometry modifiers */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->generateStrokes) {
@@ -330,8 +330,7 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
/* check if exist time modifiers */
bool BKE_gpencil_has_time_modifiers(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->remapTime) {
@@ -344,8 +343,7 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
/* Check if exist transform stroke modifiers (to rotate sculpt or edit). */
bool BKE_gpencil_has_transform_modifiers(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
/* Only if enabled in edit mode. */
if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) {
if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) ||
@@ -362,12 +360,11 @@ bool BKE_gpencil_has_transform_modifiers(Object *ob)
static int gpencil_time_modifier(
Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render)
{
- GpencilModifierData *md;
bGPdata *gpd = ob->data;
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
int nfra = cfra;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -428,9 +425,9 @@ GpencilModifierData *BKE_gpencil_modifier_new(int type)
BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
md->type = type;
- md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render |
- eGpencilModifierMode_Expanded;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render;
md->flag = eGpencilModifierFlag_OverrideLibrary_Local;
+ md->ui_expand_flag = 1; /* Only expand the parent panel at first. */
if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode) {
md->mode |= eGpencilModifierMode_Editmode;
@@ -508,7 +505,8 @@ bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
- if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && type > 0 &&
+ modifier_gpencil_types[type]->name[0] != '\0') {
return modifier_gpencil_types[type];
}
else {
@@ -516,6 +514,17 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType
}
}
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ */
+void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
+
+ strcpy(r_idname, GPENCIL_MODIFIER_TYPE_PANEL_PREFIX);
+ strcat(r_idname, mti->name);
+}
+
void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
@@ -553,6 +562,7 @@ void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
target->mode = md->mode;
target->flag = md->flag;
+ target->ui_expand_flag = md->ui_expand_flag; /* Expand the parent panel by default. */
if (mti->copyData) {
mti->copyData(md, target);
@@ -587,6 +597,26 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi
return md;
}
+void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...)
+{
+ char buffer[512];
+ va_list ap;
+ const char *format = TIP_(_format);
+
+ va_start(ap, _format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ if (md->error) {
+ MEM_freeN(md->error);
+ }
+
+ md->error = BLI_strdup(buffer);
+
+ CLOG_STR_ERROR(&LOG, md->error);
+}
+
void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 669539ca574..c3c67b9ed51 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -732,14 +732,14 @@ void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
IDP_FreeProperty(prop);
}
-IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name)
+IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
{
BLI_assert(prop->type == IDP_GROUP);
return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
}
/** same as above but ensure type match */
-IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type)
+IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
{
IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
return (idprop && idprop->type == type) ? idprop : NULL;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index b4a3f249c63..bb793b58a1d 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -360,13 +360,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
ima->rr = NULL;
}
- if (!G.background) {
- /* Background mode doesn't use OpenGL,
- * so we can avoid freeing GPU images and save some
- * time by skipping mutex lock.
- */
- GPU_free_image(ima);
- }
+ GPU_free_image(ima);
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
tile->ok = IMA_OK;
@@ -648,7 +642,7 @@ char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
void BKE_image_alpha_mode_from_extension(Image *image)
{
- image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->name);
+ image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->filepath);
}
Image *BKE_image_load(Main *bmain, const char *filepath)
@@ -668,7 +662,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
close(file);
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
- STRNCPY(ima->name, filepath);
+ STRNCPY(ima->filepath, filepath);
if (BLI_path_extension_check_array(filepath, imb_ext_movie)) {
ima->source = IMA_SRC_MOVIE;
@@ -694,7 +688,7 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
/* first search an identical filepath */
for (ima = bmain->images.first; ima; ima = ima->id.next) {
if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
- STRNCPY(strtest, ima->name);
+ STRNCPY(strtest, ima->filepath);
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &ima->id));
if (BLI_path_cmp(strtest, str) == 0) {
@@ -830,7 +824,7 @@ Image *BKE_image_add_generated(Main *bmain,
int view_id;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
- /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */
+ /* STRNCPY(ima->filepath, name); */ /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
ima->gen_y = height;
ima->gen_type = gen_type;
@@ -846,7 +840,7 @@ Image *BKE_image_add_generated(Main *bmain,
for (view_id = 0; view_id < 2; view_id++) {
ImBuf *ibuf;
ibuf = add_ibuf_size(
- width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
+ width, height, ima->filepath, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
int index = tiled ? 0 : IMA_NO_INDEX;
int entry = tiled ? 1001 : 0;
image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry);
@@ -881,7 +875,7 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
ima = image_alloc(bmain, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
if (ima) {
- STRNCPY(ima->name, ibuf->name);
+ STRNCPY(ima->filepath, ibuf->name);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
ImageTile *tile = BKE_image_get_tile(ima, 0);
tile->ok = IMA_OK_LOADED;
@@ -981,9 +975,9 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
if (totfiles == 1) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
BLI_addtail(&ima->packedfiles, imapf);
- imapf->packedfile = BKE_packedfile_new(reports, ima->name, basepath);
+ imapf->packedfile = BKE_packedfile_new(reports, ima->filepath, basepath);
if (imapf->packedfile) {
- STRNCPY(imapf->filepath, ima->name);
+ STRNCPY(imapf->filepath, ima->filepath);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
@@ -1020,7 +1014,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports,
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = BKE_packedfile_new_from_memory(data, data_len);
- STRNCPY(imapf->filepath, ima->name);
+ STRNCPY(imapf->filepath, ima->filepath);
}
}
@@ -3385,7 +3379,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* Here we ensure original image path wouldn't be used when saving
* generated image.
*/
- ima->name[0] = '\0';
+ ima->filepath[0] = '\0';
}
if (ima->source != IMA_SRC_TILED) {
@@ -3643,7 +3637,7 @@ bool BKE_image_fill_tile(struct Image *ima,
image_free_tile(ima, tile);
ImBuf *tile_ibuf = add_ibuf_size(
- width, height, ima->name, planes, is_float, gen_type, color, &ima->colorspace_settings);
+ width, height, ima->filepath, planes, is_float, gen_type, color, &ima->colorspace_settings);
if (tile_ibuf != NULL) {
image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number);
@@ -3807,7 +3801,7 @@ bool BKE_image_is_openexr(struct Image *ima)
{
#ifdef WITH_OPENEXR
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
- return BLI_path_extension_check(ima->name, ".exr");
+ return BLI_path_extension_check(ima->filepath, ".exr");
}
#else
UNUSED_VARS(ima);
@@ -4893,7 +4887,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
}
ibuf = add_ibuf_size(ima->gen_x,
ima->gen_y,
- ima->name,
+ ima->filepath,
ima->gen_depth,
(ima->gen_flag & IMA_GEN_FLOAT) != 0,
ima->gen_type,
@@ -5300,11 +5294,11 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
BLI_strncpy(filepath, iv->filepath, FILE_MAX);
}
else {
- BLI_strncpy(filepath, ima->name, FILE_MAX);
+ BLI_strncpy(filepath, ima->filepath, FILE_MAX);
}
}
else {
- BLI_strncpy(filepath, ima->name, FILE_MAX);
+ BLI_strncpy(filepath, ima->filepath, FILE_MAX);
}
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
@@ -5461,7 +5455,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
int BKE_image_sequence_guess_offset(Image *image)
{
- return BLI_path_sequence_decode(image->name, NULL, NULL, NULL);
+ return BLI_path_sequence_decode(image->filepath, NULL, NULL, NULL);
}
bool BKE_image_has_anim(Image *ima)
@@ -5478,7 +5472,7 @@ bool BKE_image_has_filepath(Image *ima)
{
/* This could be improved to detect cases like //../../, currently path
* remapping empty file paths empty. */
- return ima->name[0] != '\0';
+ return ima->filepath[0] != '\0';
}
/* Checks the image buffer changes with time (not keyframed values). */
@@ -5653,14 +5647,14 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
for (i = 0; i < 2; i++) {
- image_add_view(ima, names[i], ima->name);
+ image_add_view(ima, names[i], ima->filepath);
}
return;
}
else {
/* R_IMF_VIEWS_INDIVIDUAL */
char prefix[FILE_MAX] = {'\0'};
- char *name = ima->name;
+ char *name = ima->filepath;
const char *ext = NULL;
BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index c034fe895a6..19eb3380b8e 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -73,7 +73,7 @@ static void image_save_post(ReportList *reports,
if (opts->do_newpath) {
BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->name, filepath, sizeof(ima->name));
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
}
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -106,7 +106,7 @@ static void image_save_post(ReportList *reports,
/* only image path, never ibuf */
if (opts->relative) {
const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
- BLI_path_rel(ima->name, relbase); /* only after saving */
+ BLI_path_rel(ima->filepath, relbase); /* only after saving */
}
ColorManagedColorspaceSettings old_colorspace_settings;
@@ -135,7 +135,7 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
/**
* \return success.
- * \note ``ima->name`` and ``ibuf->name`` should end up the same.
+ * \note ``ima->filepath`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool image_save_single(ReportList *reports,
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index ab9b11f436a..7c09ae51344 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -114,7 +114,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
* Also note that the id _must_ have a library - campbell */
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
{
- const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath};
+ const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
BKE_bpath_traverse_id(bmain,
id,
@@ -160,7 +160,7 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
BKE_lib_libblock_session_uuid_renew(id);
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
- * ones are two completely different data-blocks that were virtually remaped, even though in
+ * ones are two completely different data-blocks that were virtually remapped, even though in
* reality they remain the same data. For undo this info is critical now. */
DEG_id_tag_update_ex(bmain, id, ID_RECALC_COPY_ON_WRITE);
ID *id_iter;
@@ -225,7 +225,7 @@ void id_us_ensure_real(ID *id)
CLOG_ERROR(&LOG,
"ID user count error: %s (from '%s')",
id->name,
- id->lib ? id->lib->filepath : "[Main]");
+ id->lib ? id->lib->filepath_abs : "[Main]");
BLI_assert(0);
}
id->us = limit + 1;
@@ -283,7 +283,7 @@ void id_us_min(ID *id)
CLOG_ERROR(&LOG,
"ID user decrement error: %s (from '%s'): %d <= %d",
id->name,
- id->lib ? id->lib->filepath : "[Main]",
+ id->lib ? id->lib->filepath_abs : "[Main]",
id->us,
limit);
if (GS(id->name) != ID_IP) {
@@ -446,9 +446,9 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
- * \note Always set ID->newid pointer in case it gets duplicated...
+ * \note Always set #ID.newid pointer in case it gets duplicated.
*
- * \param lib_local: Special flag used when making a whole library's content local,
+ * \param flags: Special flag used when making a whole library's content local,
* it needs specific handling.
*
* \return true if the block can be made local.
@@ -608,6 +608,49 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid)
}
/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * newid, unless test. Returns true if the block can be copied.
+ */
+ID *BKE_id_copy_for_duplicate(Main *bmain,
+ ID *id,
+ const bool is_owner_id_liboverride,
+ const eDupli_ID_Flags duplicate_flags)
+{
+ if (id == NULL) {
+ return NULL;
+ }
+ if (id->newid == NULL) {
+ if (!is_owner_id_liboverride || !ID_IS_LINKED(id)) {
+ ID *id_new;
+ BKE_id_copy(bmain, id, &id_new);
+ /* Copying add one user by default, need to get rid of that one. */
+ id_us_min(id_new);
+ ID_NEW_SET(id, id_new);
+
+ /* Shape keys are always copied with their owner ID, by default. */
+ ID *key_new = (ID *)BKE_key_from_id(id_new);
+ ID *key = (ID *)BKE_key_from_id(id);
+ if (key != NULL) {
+ ID_NEW_SET(key, key_new);
+ }
+
+ /* Note: embedded data (root nodetrees and master collections) should never be referenced by
+ * anything else, so we do not need to set their newid pointer and flag. */
+
+ if (duplicate_flags & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, id_new, true);
+ if (key_new != NULL) {
+ BKE_animdata_copy_id_action(bmain, key_new, true);
+ }
+ /* Note that actions of embedded data (root nodetrees and master collections) are handled
+ * by `BKE_animdata_copy_id_action` as well. */
+ }
+ }
+ }
+ return id->newid;
+}
+
+/**
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note Most internal ID data itself is not swapped (only IDProperties are).
*/
@@ -636,6 +679,9 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
/* Exception: IDProperties. */
id_a->properties = id_b_back.properties;
id_b->properties = id_a_back.properties;
+ /* Exception: recalc flags. */
+ id_a->recalc = id_b_back.recalc;
+ id_b->recalc = id_a_back.recalc;
}
if (bmain != NULL) {
@@ -1183,7 +1229,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
/* We may need our own flag to control that at some point, but for now 'no main' one should be
* good enough. */
- if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && id->override_library != NULL) {
+ if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && ID_IS_OVERRIDE_LIBRARY(id)) {
/* We do not want to copy existing override rules here, as they would break the proper
* remapping between IDs. Proper overrides rules will be re-generated anyway. */
BKE_lib_override_library_copy(new_id, id, false);
@@ -2129,13 +2175,18 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa
*/
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const ID *id,
+ const bool add_lib_hint,
char separator_char)
{
- name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' ';
- name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
- name[2] = ' ';
+ int i = 0;
+
+ if (add_lib_hint) {
+ name[i++] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' ';
+ }
+ name[i++] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
+ name[i++] = ' ';
- BKE_id_full_name_get(name + 3, id, separator_char);
+ BKE_id_full_name_get(name + i, id, separator_char);
}
/**
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 6fce898fd1e..9d7671322ea 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -24,6 +24,7 @@
/* all types are needed here, in order to do memory operations */
#include "DNA_ID.h"
+#include "DNA_key_types.h"
#include "BLI_utildefines.h"
@@ -32,6 +33,7 @@
#include "BKE_anim_data.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
+#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
@@ -148,6 +150,13 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
}
+ if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
+ Key *key = BKE_key_from_id(id);
+ if (key != NULL) {
+ BKE_id_free_ex(bmain, &key->id, flag, use_flag_from_idtag);
+ }
+ }
+
BKE_libblock_free_datablock(id, flag);
/* avoid notifying on removed data */
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index d6f037f64a4..457d096f983 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -27,11 +27,15 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
+#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "BKE_armature.h"
+#include "BKE_idtype.h"
+#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
@@ -40,6 +44,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "RNA_access.h"
@@ -113,7 +118,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
/** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */
void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy)
{
- BLI_assert(src_id->override_library != NULL);
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id));
if (dst_id->override_library != NULL) {
if (src_id->override_library == NULL) {
@@ -125,6 +130,7 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
}
}
else if (src_id->override_library == NULL) {
+ /* Virtual overrides of embedded data does not require any extra work. */
return;
}
else {
@@ -198,6 +204,16 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
BKE_lib_override_library_init(local_id, reference_id);
+ /* Note: From liboverride perspective (and RNA one), shape keys are considered as local embedded
+ * data-blocks, just like root node trees or master collections. Therefore, we never need to
+ * create overrides for them. We need a way to mark them as overrides though. */
+ Key *reference_key;
+ if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ Key *local_key = BKE_key_from_id(local_id);
+ BLI_assert(local_key != NULL);
+ local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE;
+ }
+
return local_id;
}
@@ -212,6 +228,12 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *local_id = lib_override_library_create_from(bmain, reference_id);
if (do_tagged_remap) {
+ Key *reference_key, *local_key = NULL;
+ if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ local_key = BKE_key_from_id(local_id);
+ BLI_assert(local_key != NULL);
+ }
+
ID *other_id;
FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
@@ -222,6 +244,13 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
reference_id,
local_id,
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ if (reference_key != NULL) {
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ &reference_key->id,
+ &local_key->id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
}
}
FOREACH_MAIN_ID_END;
@@ -246,14 +275,15 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
bool BKE_lib_override_library_create_from_tag(Main *bmain)
{
ID *reference_id;
- bool ret = true;
+ bool success = true;
ListBase todo_ids = {NULL};
LinkData *todo_id_iter;
/* Get all IDs we want to override. */
FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
- if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL &&
+ BKE_idtype_idcode_is_linkable(GS(reference_id->name))) {
todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
todo_id_iter->data = reference_id;
BLI_addtail(&todo_ids, todo_id_iter);
@@ -265,44 +295,77 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
reference_id = todo_id_iter->data;
if ((reference_id->newid = lib_override_library_create_from(bmain, reference_id)) == NULL) {
- ret = false;
+ success = false;
+ break;
}
- else {
+ /* We also tag the new IDs so that in next step we can remap their pointers too. */
+ reference_id->newid->tag |= LIB_TAG_DOIT;
+
+ Key *reference_key;
+ if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ reference_key->id.tag |= LIB_TAG_DOIT;
+
+ Key *local_key = BKE_key_from_id(reference_id->newid);
+ BLI_assert(local_key != NULL);
+ reference_key->id.newid = &local_key->id;
/* We also tag the new IDs so that in next step we can remap their pointers too. */
- reference_id->newid->tag |= LIB_TAG_DOIT;
+ local_key->id.tag |= LIB_TAG_DOIT;
}
}
/* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
* existing linked IDs usages. */
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- ID *other_id;
- reference_id = todo_id_iter->data;
+ if (success) {
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ ID *other_id;
+ reference_id = todo_id_iter->data;
+ ID *local_id = reference_id->newid;
+
+ if (local_id == NULL) {
+ continue;
+ }
- if (reference_id->newid == NULL) {
- continue;
- }
+ Key *reference_key, *local_key = NULL;
+ if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ local_key = BKE_key_from_id(reference_id->newid);
+ BLI_assert(local_key != NULL);
+ }
- /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped
- * to use newly created overriding IDs, if needed. */
- FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
- if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
- ID *local_id = reference_id->newid;
- /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
- * local IDs usages anyway... */
- BKE_libblock_relink_ex(bmain,
- other_id,
- reference_id,
- local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ /* Still checking the whole Main, that way we can tag other local IDs as needing to be
+ * remapped to use newly created overriding IDs, if needed. */
+ FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
+ /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
+ * local IDs usages anyway... */
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ if (reference_key != NULL) {
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ &reference_key->id,
+ &local_key->id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
+ }
}
+ FOREACH_MAIN_ID_END;
+ }
+ }
+ else {
+ /* We need to cleanup potentially already created data. */
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ reference_id = todo_id_iter->data;
+ BKE_id_delete(bmain, reference_id->newid);
+ reference_id->newid = NULL;
}
- FOREACH_MAIN_ID_END;
}
BLI_freelistN(&todo_ids);
- return ret;
+ return success;
}
/* We only build override GHash on request. */
@@ -310,7 +373,8 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure(
IDOverrideLibrary *override)
{
if (override->runtime == NULL) {
- override->runtime = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+ override->runtime = BLI_ghash_new(
+ BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) {
BLI_ghash_insert(override->runtime, op->rna_path, op);
}
@@ -469,7 +533,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
}
- /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index.
+ */
if (!strict && (subitem_locindex != subitem_defindex) &&
(opop = BLI_listbase_bytes_find(
&override_property->operations,
@@ -617,7 +682,7 @@ bool BKE_lib_override_library_property_operation_operands_validate(
* \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
{
- BLI_assert(local->override_library != NULL);
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
ID *reference = local->override_library->reference;
@@ -649,6 +714,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
&rnaptr_local,
&rnaptr_reference,
NULL,
+ 0,
local->override_library,
RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
@@ -672,7 +738,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
* \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
{
- BLI_assert(local->override_library != NULL);
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
ID *reference = local->override_library->reference;
@@ -712,6 +778,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
&rnaptr_local,
&rnaptr_reference,
NULL,
+ 0,
local->override_library,
RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
NULL)) {
@@ -735,9 +802,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
* Generating diff values and applying overrides are much cheaper.
*
* \return true if new overriding op was created, or some local data was reset. */
-bool BKE_lib_override_library_operations_create(Main *bmain,
- ID *local,
- const bool UNUSED(force_auto))
+bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(local->override_library != NULL);
const bool is_template = (local->override_library->reference == NULL);
@@ -752,9 +817,9 @@ bool BKE_lib_override_library_operations_create(Main *bmain,
}
if (GS(local->name) == ID_OB) {
- /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure
- * this is valid, but in some situations (like hidden collections etc.) this won't be the
- * case, so we need to take care of this ourselves. */
+ /* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would
+ * ensure this is valid, but in some situations (like hidden collections etc.) this won't
+ * be the case, so we need to take care of this ourselves. */
Object *ob_local = (Object *)local;
if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL &&
ob_local->pose->flag & POSE_RECALC) {
@@ -771,6 +836,7 @@ bool BKE_lib_override_library_operations_create(Main *bmain,
&rnaptr_local,
&rnaptr_reference,
NULL,
+ 0,
local->override_library,
RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE,
&report_flags);
@@ -792,29 +858,51 @@ bool BKE_lib_override_library_operations_create(Main *bmain,
return ret;
}
+static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata)
+{
+ Main *bmain = BLI_task_pool_user_data(pool);
+ ID *id = taskdata;
+
+ BKE_lib_override_library_operations_create(bmain, id);
+}
+
/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
void BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
{
ID *id;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(BKE_lib_override_library_main_operations_create);
+#endif
+
/* When force-auto is set, we also remove all unused existing override properties & operations.
*/
if (force_auto) {
BKE_lib_override_library_main_tag(bmain, IDOVERRIDE_LIBRARY_TAG_UNUSED, true);
}
+ TaskPool *task_pool = BLI_task_pool_create(bmain, TASK_PRIORITY_HIGH);
+
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) ||
+ if ((ID_IS_OVERRIDE_LIBRARY_REAL(id) && force_auto) ||
(id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH)) {
- BKE_lib_override_library_operations_create(bmain, id, force_auto);
+ BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL);
id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH;
}
}
FOREACH_MAIN_ID_END;
+ BLI_task_pool_work_and_wait(task_pool);
+
+ BLI_task_pool_free(task_pool);
+
if (force_auto) {
BKE_lib_override_library_main_unused_cleanup(bmain);
}
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(BKE_lib_override_library_main_operations_create);
+#endif
}
/** Set or clear given tag in all operations as unused in that override property data. */
@@ -869,7 +957,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
/** Remove all tagged-as-unused properties and operations from that ID override data. */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
{
- if (local->override_library != NULL) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
LISTBASE_FOREACH_MUTABLE (
IDOverrideLibraryProperty *, op, &local->override_library->properties) {
if (op->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) {
@@ -902,7 +990,7 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
- if (local->override_library == NULL || local->override_library->reference == NULL) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
return;
}
@@ -924,8 +1012,8 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
* So we work on temp copy of reference, and 'swap' its content with local. */
/* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
- * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will
- * do, as inn-efficient as it is. :/
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy
+ * will do, as inn-efficient as it is. :/
* Actually, maybe not! Since we are swapping with original ID's local content, we want to
* keep user-count in correct state when freeing tmp_id
* (and that user-counts of IDs used by 'new' local data also remain correct). */
@@ -942,11 +1030,21 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
}
/* This ID name is problematic, since it is an 'rna name property' it should not be editable or
- * different from reference linked ID. But local ID names need to be unique in a given type list
- * of Main, so we cannot always keep it identical, which is why we need this special manual
- * handling here. */
+ * different from reference linked ID. But local ID names need to be unique in a given type
+ * list of Main, so we cannot always keep it identical, which is why we need this special
+ * manual handling here. */
BLI_strncpy(tmp_id->name, local->name, sizeof(tmp_id->name));
+ /* Those ugly loopback pointers again... Luckily we only need to deal with the shape keys here,
+ * collections' parents are fully runtime and reconstructed later. */
+ Key *local_key = BKE_key_from_id(local);
+ Key *tmp_key = BKE_key_from_id(tmp_id);
+ if (local_key != NULL && tmp_key != NULL) {
+ /* This is some kind of hard-coded 'always enforced override'... */
+ tmp_key->from = local_key->from;
+ tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
+ }
+
PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
RNA_id_pointer_create(local, &rnaptr_src);
RNA_id_pointer_create(tmp_id, &rnaptr_dst);
@@ -978,9 +1076,9 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK;
/* Full rebuild of Depsgraph! */
-
- /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
- DEG_on_visible_update(bmain, true);
+ /* Note: this is really brute force, in theory updates from RNA should have handle this already,
+ * but for now let's play it safe. */
+ DEG_relations_tag_update(bmain);
}
/** Update all overrides from given \a bmain. */
@@ -1028,17 +1126,16 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
OverrideLibraryStorage *override_storage,
ID *local)
{
- BLI_assert(local->override_library != NULL);
- BLI_assert(override_storage != NULL);
- const bool is_template = (local->override_library->reference == NULL);
-
- if (is_template) {
+ if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) {
/* This is actually purely local data with an override template, nothing to do here! */
return NULL;
}
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
+ BLI_assert(override_storage != NULL);
+
/* Forcefully ensure we know about all needed override operations. */
- BKE_lib_override_library_operations_create(bmain, local, false);
+ BKE_lib_override_library_operations_create(bmain, local);
ID *storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
@@ -1046,8 +1143,8 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
#endif
/* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy
- * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib reference-counting
- * completely (shallow copy...). */
+ * never-overridable data (like Mesh geometry etc.)? And also maybe avoid lib
+ * reference-counting completely (shallow copy...). */
/* This would imply change in handling of user-count all over RNA
* (and possibly all over Blender code).
* Not impossible to do, but would rather see first is extra useless usual user handling is
@@ -1080,7 +1177,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
- BLI_assert(local->override_library != NULL);
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
/* Nothing else to do here really, we need to keep all temp override storage data-blocks in
* memory until whole file is written anyway (otherwise we'd get mem pointers overlap...). */
@@ -1089,8 +1186,8 @@ void BKE_lib_override_library_operations_store_end(
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage)
{
- /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost'
- * copies of IDs without increasing usercount of used data-blocks. */
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make
+ * 'ghost' copies of IDs without increasing usercount of used data-blocks. */
ID *id;
FOREACH_MAIN_ID_BEGIN (override_storage, id) {
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 3026dd617b5..777a4fb9dfa 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -667,9 +667,10 @@ static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
/* See: NEW_ID macro */
if (id->newid) {
BKE_library_update_ID_link_user(id->newid, id, cb_flag);
- *id_pointer = id->newid;
+ id = id->newid;
+ *id_pointer = id;
}
- else if (id->tag & LIB_TAG_NEW) {
+ if (id->tag & LIB_TAG_NEW) {
id->tag &= ~LIB_TAG_NEW;
BKE_libblock_relink_to_newid(id);
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 64ffea22363..48c98be626d 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -81,23 +81,23 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
{
/* in some cases this is used to update the absolute path from the
* relative */
- if (lib->name != filepath) {
- BLI_strncpy(lib->name, filepath, sizeof(lib->name));
+ if (lib->filepath != filepath) {
+ BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath));
}
- BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath));
+ BLI_strncpy(lib->filepath_abs, filepath, sizeof(lib->filepath_abs));
- /* not essential but set filepath is an absolute copy of value which
- * is more useful if its kept in sync */
- if (BLI_path_is_rel(lib->filepath)) {
+ /* Not essential but set `filepath_abs` is an absolute copy of value which
+ * is more useful if its kept in sync. */
+ if (BLI_path_is_rel(lib->filepath_abs)) {
/* note that the file may be unsaved, in this case, setting the
- * filepath on an indirectly linked path is not allowed from the
+ * `filepath_abs` on an indirectly linked path is not allowed from the
* outliner, and its not really supported but allow from here for now
* since making local could cause this to be directly linked - campbell
*/
/* Never make paths relative to parent lib - reading code (blenloader) always set *all*
- * lib->name relative to current main, not to their parent for indirectly linked ones. */
+ * `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
const char *basepath = BKE_main_blendfile_path(bmain);
- BLI_path_abs(lib->filepath, basepath);
+ BLI_path_abs(lib->filepath_abs, basepath);
}
}
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index ea3bee8b2f6..4b577ccec2c 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -288,6 +288,29 @@ void BKE_main_relations_free(Main *bmain)
}
/**
+ * Remove an ID from the relations (the two entries for that ID, not the ID from entries in other
+ * IDs' relationships).
+ *
+ * Does not free any allocated memory.
+ * Allows to use those relations as a way to mark an ID as already processed, without requiring any
+ * additional tagging or GSet.
+ * Obviously, relations should be freed after use then, since this will make them fully invalid.
+ */
+void BKE_main_relations_ID_remove(Main *bmain, ID *id)
+{
+ if (bmain->relations) {
+ /* Note: we do not free the entries from the mempool, those will be dealt with when finally
+ * freeing the whole relations. */
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_remove(bmain->relations->id_used_to_user, id, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_remove(bmain->relations->id_user_to_used, id, NULL, NULL);
+ }
+ }
+}
+
+/**
* Create a GSet storing all IDs present in given \a bmain, by their pointers.
*
* \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 433db26ded8..b298a6a2787 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2112,7 +2112,7 @@ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
* Higher level functions hiding most of the code needed around call to
* #BKE_mesh_normals_loop_custom_from_vertices_set().
*
- * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
+ * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
* with automatically computed vectors.
*/
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
@@ -2386,10 +2386,10 @@ float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
* - The resulting volume will only be correct if the mesh is manifold and has consistent
* face winding (non-contiguous face normals or holes in the mesh surface).
*/
-static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
- const MLoop *loopstart,
- const MVert *mvarray,
- float r_cent[3])
+static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
{
const float *v_pivot, *v_step1;
float total_volume = 0.0f;
@@ -2424,6 +2424,36 @@ static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
}
/**
+ * A version of mesh_calc_poly_volume_centroid that takes an initial reference center,
+ * use this to increase numeric stability as the quality of the result becomes
+ * very low quality as the value moves away from 0.0, see: T65986.
+ */
+static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ const float reference_center[3],
+ float r_cent[3])
+{
+ /* See: mesh_calc_poly_volume_centroid for comments. */
+ float v_pivot[3], v_step1[3];
+ float total_volume = 0.0f;
+ zero_v3(r_cent);
+ sub_v3_v3v3(v_pivot, mvarray[loopstart[0].v].co, reference_center);
+ sub_v3_v3v3(v_step1, mvarray[loopstart[1].v].co, reference_center);
+ for (int i = 2; i < mpoly->totloop; i++) {
+ float v_step2[3];
+ sub_v3_v3v3(v_step2, mvarray[loopstart[i].v].co, reference_center);
+ const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
+ total_volume += tetra_volume;
+ for (uint j = 0; j < 3; j++) {
+ r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
+ }
+ copy_v3_v3(v_step1, v_step2);
+ }
+ return total_volume;
+}
+
+/**
* \note
* - Results won't be correct if polygon is non-planar.
* - This has the advantage over #mesh_calc_poly_volume_centroid
@@ -2536,10 +2566,35 @@ bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
if (me->totvert) {
mul_v3_fl(r_cent, 1.0f / (float)me->totvert);
}
-
return (me->totvert != 0);
}
+/**
+ * Calculate the center from polygons,
+ * use when we want to ignore vertex locations that don't have connected faces.
+ */
+bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
+{
+ int i = me->totpoly;
+ int tot = 0;
+ const MPoly *mpoly = me->mpoly;
+ const MLoop *mloop = me->mloop;
+ const MVert *mvert = me->mvert;
+ zero_v3(r_cent);
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ int loopend = mpoly->loopstart + mpoly->totloop;
+ for (int j = mpoly->loopstart; j < loopend; j++) {
+ add_v3_v3(r_cent, mvert[mloop[j].v].co);
+ }
+ tot += mpoly->totloop;
+ }
+ /* otherwise we get NAN for 0 verts */
+ if (me->totpoly) {
+ mul_v3_fl(r_cent, 1.0f / (float)tot);
+ }
+ return (me->totpoly != 0);
+}
+
bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
{
float min[3], max[3];
@@ -2595,12 +2650,16 @@ bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
float total_volume = 0.0f;
float poly_cent[3];
+ /* Use an initial center to avoid numeric instability of geometry far away from the center. */
+ float init_cent[3];
+ const bool init_cent_result = BKE_mesh_center_median_from_polys(me, init_cent);
+
zero_v3(r_cent);
/* calculate a weighted average of polyhedron centroids */
for (mpoly = me->mpoly; i--; mpoly++) {
- poly_volume = mesh_calc_poly_volume_centroid(
- mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ poly_volume = mesh_calc_poly_volume_centroid_with_reference_center(
+ mpoly, me->mloop + mpoly->loopstart, me->mvert, init_cent, poly_cent);
/* poly_cent is already volume-weighted, so no need to multiply by the volume */
add_v3_v3(r_cent, poly_cent);
@@ -2616,9 +2675,10 @@ bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
/* this can happen for non-manifold objects, fallback to median */
if (UNLIKELY(!is_finite_v3(r_cent))) {
- return BKE_mesh_center_median(me, r_cent);
+ copy_v3_v3(r_cent, init_cent);
+ return init_cent_result;
}
-
+ add_v3_v3(r_cent, init_cent);
return (me->totpoly != 0);
}
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index 3daf9f2752e..010b306ec76 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -405,6 +405,37 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source)
free_bvhtree_from_mesh(&bvhtree);
}
+void BKE_remesh_reproject_vertex_paint(Mesh *target, Mesh *source)
+{
+ BVHTreeFromMesh bvhtree = {
+ .nearest_callback = NULL,
+ };
+ BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
+
+ int tot_color_layer = CustomData_number_of_layers(&source->vdata, CD_PROP_COLOR);
+
+ for (int layer_n = 0; layer_n < tot_color_layer; layer_n++) {
+ const char *layer_name = CustomData_get_layer_name(&source->vdata, CD_PROP_COLOR, layer_n);
+ CustomData_add_layer_named(
+ &target->vdata, CD_PROP_COLOR, CD_CALLOC, NULL, target->totvert, layer_name);
+
+ MPropCol *target_color = CustomData_get_layer_n(&target->vdata, CD_PROP_COLOR, layer_n);
+ MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT);
+ MPropCol *source_color = CustomData_get_layer_n(&source->vdata, CD_PROP_COLOR, layer_n);
+ for (int i = 0; i < target->totvert; i++) {
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(
+ bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree);
+ if (nearest.index != -1) {
+ copy_v4_v4(target_color[i].color, source_color[nearest.index].color);
+ }
+ }
+ }
+ free_bvhtree_from_mesh(&bvhtree);
+}
+
struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
{
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 8bce577897b..932423bc445 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -203,26 +203,31 @@ bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
return true;
}
+bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
+{
+ EditMeshData *edit_data = mesh->runtime.edit_data;
+ if (edit_data == NULL) {
+ return false;
+ }
+
+ MEM_SAFE_FREE(edit_data->polyCos);
+ MEM_SAFE_FREE(edit_data->polyNos);
+ MEM_SAFE_FREE(edit_data->vertexCos);
+ MEM_SAFE_FREE(edit_data->vertexNos);
+
+ return true;
+}
+
bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
{
if (mesh->runtime.edit_data == NULL) {
return false;
}
+ BKE_mesh_runtime_reset_edit_data(mesh);
- if (mesh->runtime.edit_data->polyCos != NULL) {
- MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
- }
- if (mesh->runtime.edit_data->polyNos != NULL) {
- MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
- }
- if (mesh->runtime.edit_data->vertexCos != NULL) {
- MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
- }
- if (mesh->runtime.edit_data->vertexNos != NULL) {
- MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
- }
+ MEM_freeN(mesh->runtime.edit_data);
+ mesh->runtime.edit_data = NULL;
- MEM_SAFE_FREE(mesh->runtime.edit_data);
return true;
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 7c77746ea1c..327e8bfca7a 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -141,7 +141,7 @@ ModifierData *BKE_modifier_new(int type)
md->type = type;
md->mode = eModifierMode_Realtime | eModifierMode_Render;
md->flag = eModifierFlag_OverrideLibrary_Local;
- md->ui_expand_flag = 1; /* Only open the main panel at the beginning, not the subpanels. */
+ md->ui_expand_flag = 1; /* Only open the main panel at the beginning, not the sub-panels. */
if (mti->flags & eModifierTypeFlag_EnableInEditmode) {
md->mode |= eModifierMode_Editmode;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index fe7c2055aef..f0efc9b8c50 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -220,19 +220,19 @@ static void get_sequence_fname(const MovieClip *clip, const int framenr, char *n
char head[FILE_MAX], tail[FILE_MAX];
int offset;
- BLI_strncpy(name, clip->name, sizeof(clip->name));
+ BLI_strncpy(name, clip->filepath, sizeof(clip->filepath));
BLI_path_sequence_decode(name, head, tail, &numlen);
/* Movie-clips always points to first image from sequence, auto-guess offset for now.
* Could be something smarter in the future. */
- offset = sequence_guess_offset(clip->name, strlen(head), numlen);
+ offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
if (numlen) {
BLI_path_sequence_encode(
name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
}
else {
- BLI_strncpy(name, clip->name, sizeof(clip->name));
+ BLI_strncpy(name, clip->filepath, sizeof(clip->filepath));
}
BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
@@ -246,7 +246,7 @@ static void get_proxy_fname(
char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
int proxynr = framenr - clip->start_frame + 1 + clip->frame_offset;
- BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX);
+ BLI_split_dirfile(clip->filepath, clipdir, clipfile, FILE_MAX, FILE_MAX);
if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
@@ -395,7 +395,7 @@ static void movieclip_open_anim_file(MovieClip *clip)
char str[FILE_MAX];
if (!clip->anim) {
- BLI_strncpy(str, clip->name, FILE_MAX);
+ BLI_strncpy(str, clip->filepath, FILE_MAX);
BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
/* FIXME: make several stream accessible in image editor, too */
@@ -445,7 +445,7 @@ static void movieclip_calc_length(MovieClip *clip)
unsigned short numlen;
char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
- BLI_path_sequence_decode(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
if (numlen == 0) {
/* there's no number group in file name, assume it's single framed sequence */
@@ -531,10 +531,10 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
unsigned short numlen;
char head[FILE_MAX], tail[FILE_MAX];
- BLI_path_sequence_decode(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
/* see comment in get_sequence_fname */
- clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen);
+ clip->cache->sequence_offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
}
index += clip->cache->sequence_offset;
@@ -674,7 +674,7 @@ static bool put_imbuf_cache(
clip->cache->sequence_offset = -1;
if (clip->source == MCLIP_SRC_SEQUENCE) {
unsigned short numlen;
- BLI_path_sequence_decode(clip->name, NULL, NULL, &numlen);
+ BLI_path_sequence_decode(clip->filepath, NULL, NULL, &numlen);
clip->cache->is_still_sequence = (numlen == 0);
}
}
@@ -758,7 +758,7 @@ static void detect_clip_source(Main *bmain, MovieClip *clip)
ImBuf *ibuf;
char name[FILE_MAX];
- BLI_strncpy(name, clip->name, sizeof(name));
+ BLI_strncpy(name, clip->filepath, sizeof(name));
BLI_path_abs(name, BKE_main_blendfile_path(bmain));
ibuf = IMB_testiffname(name, IB_rect | IB_multilayer);
@@ -795,7 +795,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
/* create a short library name */
clip = movieclip_alloc(bmain, BLI_path_basename(name));
- BLI_strncpy(clip->name, name, sizeof(clip->name));
+ BLI_strncpy(clip->filepath, name, sizeof(clip->filepath));
detect_clip_source(bmain, clip);
@@ -821,7 +821,7 @@ MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, b
/* first search an identical filepath */
for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
- BLI_strncpy(strtest, clip->name, sizeof(clip->name));
+ BLI_strncpy(strtest, clip->filepath, sizeof(clip->filepath));
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id));
if (BLI_path_cmp(strtest, str) == 0) {
@@ -1739,7 +1739,7 @@ void BKE_movieclip_filename_for_frame(MovieClip *clip, MovieClipUser *user, char
}
}
else {
- BLI_strncpy(name, clip->name, FILE_MAX);
+ BLI_strncpy(name, clip->filepath, FILE_MAX);
BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
}
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 48c6727add5..b73f957535c 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -748,7 +748,7 @@ GHashIterator *nodeSocketTypeGetIterator(void)
return BLI_ghashIterator_new(nodesockettypes_hash);
}
-struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
+struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier)
{
bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
for (; sock; sock = sock->next) {
@@ -3216,7 +3216,7 @@ void BKE_node_clipboard_add_node(bNode *node)
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
if (ID_IS_LINKED(node->id)) {
BLI_strncpy(
- node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
+ node_info->library_name, node->id->lib->filepath_abs, sizeof(node_info->library_name));
}
else {
node_info->library_name[0] = '\0';
diff --git a/source/blender/blenkernel/intern/node_tree_ref.cc b/source/blender/blenkernel/intern/node_tree_ref.cc
index 517c1b85aff..6bd3e2d2e5a 100644
--- a/source/blender/blenkernel/intern/node_tree_ref.cc
+++ b/source/blender/blenkernel/intern/node_tree_ref.cc
@@ -18,7 +18,8 @@
#include "BLI_dot_export.hh"
-namespace BKE {
+namespace blender {
+namespace bke {
NodeTreeRef::NodeTreeRef(bNodeTree *btree) : m_btree(btree)
{
@@ -78,7 +79,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : m_btree(btree)
}
for (NodeRef *node : m_nodes_by_id) {
- m_nodes_by_idname.lookup_or_add_default(node->idname()).append(node);
+ const bNodeType *nodetype = node->m_bnode->typeinfo;
+ m_nodes_by_type.lookup_or_add_default(nodetype).append(node);
}
}
@@ -138,15 +140,13 @@ void NodeTreeRef::find_targets_skipping_reroutes(OutputSocketRef &socket,
std::string NodeTreeRef::to_dot() const
{
- namespace Dot = blender::DotExport;
+ dot::DirectedGraph digraph;
+ digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
- Dot::DirectedGraph digraph;
- digraph.set_rankdir(Dot::Attr_rankdir::LeftToRight);
-
- Map<const NodeRef *, Dot::NodeWithSocketsRef> dot_nodes;
+ Map<const NodeRef *, dot::NodeWithSocketsRef> dot_nodes;
for (const NodeRef *node : m_nodes_by_id) {
- Dot::Node &dot_node = digraph.new_node("");
+ dot::Node &dot_node = digraph.new_node("");
dot_node.set_background_color("white");
Vector<std::string> input_names;
@@ -159,13 +159,13 @@ std::string NodeTreeRef::to_dot() const
}
dot_nodes.add_new(node,
- Dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
+ dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
}
for (const OutputSocketRef *from_socket : m_output_sockets) {
for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) {
- Dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node());
- Dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node());
+ dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node());
+ dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node());
digraph.new_edge(from_dot_node.output(from_socket->index()),
to_dot_node.input(to_socket->index()));
@@ -175,4 +175,5 @@ std::string NodeTreeRef::to_dot() const
return digraph.to_dot_string();
}
-} // namespace BKE
+} // namespace bke
+} // namespace blender
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 127c5243c7e..2ddbdd02883 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1758,300 +1758,171 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
* \note Caller MUST free \a newid pointers itself (#BKE_main_id_clear_newpoins()) and call updates
* of DEG too (#DAG_relations_tag_update()).
*/
-Object *BKE_object_duplicate(Main *bmain, const Object *ob, const int dupflag)
+Object *BKE_object_duplicate(Main *bmain,
+ Object *ob,
+ const eDupli_ID_Flags dupflag,
+ const eLibIDDuplicateFlags duplicate_options)
{
+ const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
+
+ if (!is_subprocess) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+ }
+
Material ***matarar;
- ID *id;
- int a, didit;
const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob);
- Object *obn = BKE_object_copy(bmain, ob);
+ Object *obn;
+ BKE_id_copy(bmain, &ob->id, (ID **)&obn);
+ id_us_min(&obn->id);
+ if (is_subprocess) {
+ ID_NEW_SET(ob, obn);
+ }
/* 0 == full linked. */
if (dupflag == 0) {
return obn;
}
-#define ID_NEW_REMAP_US(a) \
- if ((a)->id.newid) { \
- (a) = (void *)(a)->id.newid; \
- (a)->id.us++; \
- }
-#define ID_NEW_REMAP_US2(a) \
- if (((ID *)a)->newid) { \
- (a) = ((ID *)a)->newid; \
- ((ID *)a)->us++; \
- }
-
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
BKE_animdata_copy_id_action(bmain, &obn->id, true);
}
if (dupflag & USER_DUP_MAT) {
- for (a = 0; a < obn->totcol; a++) {
- id = (ID *)obn->mat[a];
- if (id) {
- if (is_object_liboverride && ID_IS_LINKED(id)) {
- continue;
- }
- ID_NEW_REMAP_US(obn->mat[a])
- else
- {
- obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true);
- }
- }
- id_us_min(id);
- }
+ for (int i = 0; i < obn->totcol; i++) {
+ BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], is_object_liboverride, dupflag);
}
}
if (dupflag & USER_DUP_PSYS) {
ParticleSystem *psys;
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
- id = (ID *)psys->part;
- if (id) {
- if (is_object_liboverride && ID_IS_LINKED(id)) {
- continue;
- }
- ID_NEW_REMAP_US(psys->part)
- else
- {
- psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &psys->part->id, true);
- }
- }
- id_us_min(id);
- }
+ BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, is_object_liboverride, dupflag);
}
}
- id = obn->data;
- didit = 0;
+ ID *id = obn->data;
+ ID *id_new = NULL;
+ const bool need_to_duplicate_obdata = (id != NULL) && (id->newid == NULL);
- if (!is_object_liboverride || !ID_IS_LINKED(id)) {
- switch (obn->type) {
- case OB_MESH:
- if (dupflag & USER_DUP_MESH) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_CURVE:
- if (dupflag & USER_DUP_CURVE) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_SURF:
- if (dupflag & USER_DUP_SURF) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_FONT:
- if (dupflag & USER_DUP_FONT) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_MBALL:
- if (dupflag & USER_DUP_MBALL) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_LAMP:
- if (dupflag & USER_DUP_LAMP) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_light_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_ARMATURE:
- if (dupflag != 0) {
- DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY);
- if (obn->pose) {
- BKE_pose_tag_recalc(bmain, obn->pose);
- }
- if (dupflag & USER_DUP_ARM) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
- BKE_pose_rebuild(bmain, obn, obn->data, true);
- didit = 1;
- }
- id_us_min(id);
- }
- }
- break;
- case OB_LATTICE:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_CAMERA:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_LIGHTPROBE:
- if (dupflag & USER_DUP_LIGHTPROBE) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_SPEAKER:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_GPENCIL:
- if (dupflag & USER_DUP_GPENCIL) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_HAIR:
- if (dupflag & USER_DUP_HAIR) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_hair_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_POINTCLOUD:
- if (dupflag & USER_DUP_POINTCLOUD) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_pointcloud_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_VOLUME:
- if (dupflag & USER_DUP_VOLUME) {
- ID_NEW_REMAP_US2(obn->data)
- else
- {
- obn->data = ID_NEW_SET(obn->data, BKE_volume_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- }
- }
-
- /* Check if obdata is copied. */
- if (didit) {
- Key *key = BKE_key_from_object(obn);
-
- Key *oldkey = BKE_key_from_object(ob);
- if (oldkey != NULL) {
- ID_NEW_SET(oldkey, key);
- }
-
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true);
- if (key) {
- BKE_animdata_copy_id_action(bmain, (ID *)key, true);
+ switch (obn->type) {
+ case OB_MESH:
+ if (dupflag & USER_DUP_MESH) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
}
- }
+ break;
+ case OB_CURVE:
+ if (dupflag & USER_DUP_CURVE) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_SURF:
+ if (dupflag & USER_DUP_SURF) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_FONT:
+ if (dupflag & USER_DUP_FONT) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_MBALL:
+ if (dupflag & USER_DUP_MBALL) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_LAMP:
+ if (dupflag & USER_DUP_LAMP) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_ARMATURE:
+ if (dupflag & USER_DUP_ARM) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_LATTICE:
+ if (dupflag != 0) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_CAMERA:
+ if (dupflag != 0) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_LIGHTPROBE:
+ if (dupflag & USER_DUP_LIGHTPROBE) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_SPEAKER:
+ if (dupflag != 0) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_GPENCIL:
+ if (dupflag & USER_DUP_GPENCIL) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_HAIR:
+ if (dupflag & USER_DUP_HAIR) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_POINTCLOUD:
+ if (dupflag & USER_DUP_POINTCLOUD) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ case OB_VOLUME:
+ if (dupflag & USER_DUP_VOLUME) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ }
+ break;
+ }
+ /* If obdata has been copied, we may also have to duplicate the materials assigned to it. */
+ if (need_to_duplicate_obdata && id_new != NULL) {
if (dupflag & USER_DUP_MAT) {
matarar = BKE_object_material_array_p(obn);
if (matarar) {
- for (a = 0; a < obn->totcol; a++) {
- id = (ID *)(*matarar)[a];
- if (id) {
- if (is_object_liboverride && ID_IS_LINKED(id)) {
- continue;
- }
- ID_NEW_REMAP_US((*matarar)[a])
- else
- {
- (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a]));
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &(*matarar)[a]->id, true);
- }
- }
- id_us_min(id);
- }
+ for (int i = 0; i < obn->totcol; i++) {
+ BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], is_object_liboverride, dupflag);
}
}
}
}
-#undef ID_NEW_REMAP_US
-#undef ID_NEW_REMAP_US2
+ if (!is_subprocess) {
+ /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/
+ BKE_libblock_relink_to_newid(&obn->id);
+
+#ifndef NDEBUG
+ /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0);
+ }
+ FOREACH_MAIN_ID_END;
+#endif
+
+ /* Cleanup. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+ }
+
+ if (obn->type == OB_ARMATURE) {
+ DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY);
+ if (obn->pose) {
+ BKE_pose_tag_recalc(bmain, obn->pose);
+ }
+ // BKE_pose_rebuild(bmain, obn, obn->data, true);
+ }
- if (ob->data != NULL) {
+ if (obn->data != NULL) {
DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS);
}
@@ -2512,7 +2383,6 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
}
/**
- * \param depsgraph: Used for dupli-frame time.
* \return success if \a mat is set.
*/
static bool ob_parcurve(Object *ob, Object *par, float mat[4][4])
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index c5ef5acb08b..d8c3e0bf714 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -183,7 +183,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
#endif
/* Always compute UVs, vertex colors as orcos for render. */
cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
- cddata_masks.vmask |= CD_MASK_ORCO;
+ cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
if (em) {
makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index ff6aa09ec89..2cd5588ccb8 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -264,14 +264,16 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) &&
BKE_vfont_is_builtin(vfont) == false) {
- vfont->packedfile = BKE_packedfile_new(reports, vfont->name, BKE_main_blendfile_path(bmain));
+ vfont->packedfile = BKE_packedfile_new(
+ reports, vfont->filepath, BKE_main_blendfile_path(bmain));
tot++;
}
}
for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
- sound->packedfile = BKE_packedfile_new(reports, sound->name, BKE_main_blendfile_path(bmain));
+ sound->packedfile = BKE_packedfile_new(
+ reports, sound->filepath, BKE_main_blendfile_path(bmain));
tot++;
}
}
@@ -566,14 +568,14 @@ int BKE_packedfile_unpack_vfont(Main *bmain,
if (vfont != NULL) {
unpack_generate_paths(
- vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
+ vfont->filepath, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
newname = BKE_packedfile_unpack_to_file(
reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
if (newname != NULL) {
ret_value = RET_OK;
BKE_packedfile_free(vfont->packedfile);
vfont->packedfile = NULL;
- BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
+ BLI_strncpy(vfont->filepath, newname, sizeof(vfont->filepath));
MEM_freeN(newname);
}
}
@@ -592,11 +594,11 @@ int BKE_packedfile_unpack_sound(Main *bmain,
if (sound != NULL) {
unpack_generate_paths(
- sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
+ sound->filepath, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
newname = BKE_packedfile_unpack_to_file(
reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
if (newname != NULL) {
- BLI_strncpy(sound->name, newname, sizeof(sound->name));
+ BLI_strncpy(sound->filepath, newname, sizeof(sound->filepath));
MEM_freeN(newname);
BKE_packedfile_free(sound->packedfile);
@@ -644,7 +646,7 @@ int BKE_packedfile_unpack_image(Main *bmain,
/* keep the new name in the image for non-pack specific reasons */
if (how != PF_REMOVE) {
- BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ BLI_strncpy(ima->filepath, newname, sizeof(imapf->filepath));
}
MEM_freeN(newname);
}
@@ -701,12 +703,12 @@ int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports)
int ret_value = RET_ERROR;
for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
- if (lib->packedfile && lib->name[0]) {
+ if (lib->packedfile && lib->filepath[0]) {
newname = BKE_packedfile_unpack_to_file(reports,
BKE_main_blendfile_path(bmain),
- lib->filepath,
- lib->filepath,
+ lib->filepath_abs,
+ lib->filepath_abs,
lib->packedfile,
PF_WRITE_ORIGINAL);
if (newname != NULL) {
@@ -731,19 +733,19 @@ void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
/* test for relativenss */
for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
- if (!BLI_path_is_rel(lib->name)) {
+ if (!BLI_path_is_rel(lib->filepath)) {
break;
}
}
if (lib) {
- BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
+ BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->filepath);
return;
}
for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
if (lib->packedfile == NULL) {
- lib->packedfile = BKE_packedfile_new(reports, lib->name, BKE_main_blendfile_path(bmain));
+ lib->packedfile = BKE_packedfile_new(reports, lib->filepath, BKE_main_blendfile_path(bmain));
}
}
}
@@ -844,7 +846,7 @@ void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF
}
case ID_LI: {
Library *li = (Library *)id;
- BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
+ BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->filepath);
break;
}
default:
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index f26b478c680..b3ab856468c 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1310,7 +1310,7 @@ static void sculptsession_free_pbvh(Object *object)
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
- MEM_SAFE_FREE(ss->layer_base);
+ MEM_SAFE_FREE(ss->persistent_base);
MEM_SAFE_FREE(ss->preview_vert_index_list);
ss->preview_vert_index_count = 0;
@@ -1368,6 +1368,9 @@ void BKE_sculptsession_free(Object *ob)
MEM_SAFE_FREE(ss->preview_vert_index_list);
+ MEM_SAFE_FREE(ss->vertex_info.connected_component);
+ MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index);
+
if (ss->pose_ik_chain_preview) {
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments[i].weights);
@@ -1474,8 +1477,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
/**
* \param need_mask: So that the evaluated mesh that is returned has mask data.
*/
-static void sculpt_update_object(
- Depsgraph *depsgraph, Object *ob, Mesh *me_eval, bool need_pmap, bool need_mask)
+static void sculpt_update_object(Depsgraph *depsgraph,
+ Object *ob,
+ Mesh *me_eval,
+ bool need_pmap,
+ bool need_mask,
+ bool need_colors)
{
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
@@ -1490,6 +1497,8 @@ static void sculpt_update_object(
ss->building_vp_handle = false;
+ ss->scene = scene;
+
if (need_mask) {
if (mmd == NULL) {
if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
@@ -1503,6 +1512,16 @@ static void sculpt_update_object(
}
}
+ /* Add a color layer if a color tool is used. */
+ Mesh *orig_me = BKE_object_get_original_mesh(ob);
+ if (need_colors) {
+ if (!CustomData_has_layer(&orig_me->vdata, CD_PROP_COLOR)) {
+ CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
+ BKE_mesh_update_customdata_pointers(orig_me, true);
+ DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY);
+ }
+ }
+
/* tessfaces aren't used and will become invalid */
BKE_mesh_tessface_clear(me);
@@ -1535,6 +1554,7 @@ static void sculpt_update_object(
ss->multires.modifier = NULL;
ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
}
/* Sculpt Face Sets. */
@@ -1663,13 +1683,11 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
BLI_assert(me_eval != NULL);
- sculpt_update_object(depsgraph, ob_orig, me_eval, false, false);
+ sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false);
}
-void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph,
- Object *ob_orig,
- bool need_pmap,
- bool need_mask)
+void BKE_sculpt_update_object_for_edit(
+ Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
/* Update from sculpt operators and undo, to update sculpt session
* and PBVH after edits. */
@@ -1679,7 +1697,7 @@ void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph,
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
- sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask);
+ sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index c201cb83c44..b589db33edb 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2262,6 +2262,7 @@ static void do_path_effectors(ParticleSimulationData *sim,
sim->psys->part->effector_weights,
&epoint,
force,
+ NULL,
NULL);
mul_v3_fl(force,
@@ -4786,7 +4787,7 @@ void psys_get_dupli_texture(ParticleSystem *psys,
int num;
/* XXX: on checking '(psmd->dm != NULL)'
- * This is incorrect but needed for metaball evaluation.
+ * This is incorrect but needed for meta-ball evaluation.
* Ideally this would be calculated via the depsgraph, however with meta-balls,
* the entire scenes dupli's are scanned, which also looks into uncalculated data.
*
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 606291a9ae0..d09f9a8eb09 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -2243,8 +2243,13 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
/* add effectors */
pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR) {
- BKE_effectors_apply(
- sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
+ BKE_effectors_apply(sim->psys->effectors,
+ sim->colliders,
+ part->effector_weights,
+ &epoint,
+ force,
+ NULL,
+ impulse);
}
mul_v3_fl(force, efdata->ptex.field);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 19f28047b80..8d7dabf9859 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1325,6 +1325,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
+ CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR),
update_flags);
break;
case PBVH_BMESH:
@@ -1442,6 +1443,10 @@ void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flag)
pbvh_update_mask_redraw(pbvh, nodes, totnode, flag);
}
+ if (flag & (PBVH_UpdateColor)) {
+ /* Do nothing */
+ }
+
if (flag & (PBVH_UpdateVisibility)) {
pbvh_update_visibility_redraw(pbvh, nodes, totnode, flag);
}
@@ -1729,6 +1734,11 @@ void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
+void BKE_pbvh_node_mark_update_color(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateColor | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+}
+
void BKE_pbvh_node_mark_update_visibility(PBVHNode *node)
{
node->flag |= PBVH_UpdateVisibility | PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers |
@@ -2905,6 +2915,26 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
*r_tot = tot;
}
+PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node)
+{
+
+ if (!node->color_buffer.color) {
+ node->color_buffer.color = MEM_callocN(node->uniq_verts * sizeof(float) * 4, "Color buffer");
+ }
+ return &node->color_buffer;
+}
+
+void BKE_pbvh_node_color_buffer_free(PBVH *pbvh)
+{
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ for (int i = 0; i < totnode; i++) {
+ MEM_SAFE_FREE(nodes[i]->color_buffer.color);
+ }
+ MEM_SAFE_FREE(nodes);
+}
+
void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
{
struct CCGElem **grids;
@@ -2958,6 +2988,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->mask = NULL;
if (pbvh->type == PBVH_FACES) {
vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
+ vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR);
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 7397f939894..6f8bae822ea 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -105,6 +105,9 @@ struct PBVHNode {
float (*bm_orco)[3];
int (*bm_ortri)[3];
int bm_tot_ortri;
+
+ /* Used to store the brush color during a stroke and composite it over the original color */
+ PBVHColorBufferNode color_buffer;
};
typedef enum {
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 836fe59d7bd..ab392e50053 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1062,7 +1062,7 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
FluidModifierData *mmd = (FluidModifierData *)smoke_v;
FluidDomainSettings *mds = mmd->domain;
- OpenVDBWriter_set_flags(writer, mds->openvdb_comp, (mds->data_depth == 16));
+ OpenVDBWriter_set_flags(writer, mds->openvdb_compression, (mds->openvdb_data_depth == 16));
OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", mds->active_fields);
OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", mds->res);
@@ -1593,7 +1593,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = sb;
pid->type = PTCACHE_TYPE_SOFTBODY;
pid->cache = sb->shared->pointcache;
@@ -1632,7 +1632,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
{
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = psys;
pid->type = PTCACHE_TYPE_PARTICLES;
pid->stack_index = psys->pointcache->index;
@@ -1697,7 +1697,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
{
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = clmd;
pid->type = PTCACHE_TYPE_CLOTH;
pid->stack_index = clmd->point_cache->index;
@@ -1738,7 +1738,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidMo
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = mmd;
pid->type = PTCACHE_TYPE_SMOKE_DOMAIN;
@@ -1788,7 +1788,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = surface;
pid->type = PTCACHE_TYPE_DYNAMICPAINT;
pid->cache = surface->pointcache;
@@ -1829,7 +1829,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
memset(pid, 0, sizeof(PTCacheID));
- pid->ob = ob;
+ pid->owner_id = &ob->id;
pid->calldata = rbw;
pid->type = PTCACHE_TYPE_RIGIDBODY;
pid->cache = rbw->shared->pointcache;
@@ -2188,9 +2188,9 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
- Library *lib = (pid->ob) ? pid->ob->id.lib : NULL;
+ Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
- lib->filepath :
+ lib->filepath_abs :
BKE_main_blendfile_path_from_global();
size_t i;
@@ -2246,7 +2246,7 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
newname += len;
}
if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- idname = (pid->ob->id.name + 2);
+ idname = (pid->owner_id->name + 2);
/* convert chars to hex so they are always a valid filename */
while ('\0' != *idname) {
BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (unsigned int)(*idname++));
@@ -2263,7 +2263,8 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
if (do_ext) {
if (pid->cache->index < 0) {
- pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob);
+ BLI_assert(GS(pid->owner_id->name) == ID_OB);
+ pid->cache->index = pid->stack_index = BKE_object_insert_ptcache((Object *)pid->owner_id);
}
const char *ext = ptcache_file_extension(pid);
@@ -2297,7 +2298,7 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
#ifndef DURIAN_POINTCACHE_LIB_OK
/* don't allow writing for linked objects */
- if (pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) {
+ if (pid->owner_id->lib && mode == PTCACHE_FILE_WRITE) {
return NULL;
}
#endif
@@ -3508,7 +3509,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
#ifndef DURIAN_POINTCACHE_LIB_OK
/* don't allow clearing for linked objects */
- if (pid->ob->id.lib) {
+ if (pid->owner_id->lib) {
return;
}
#endif
@@ -3688,7 +3689,6 @@ void BKE_ptcache_id_time(
* is probably to interpolate results from two frames for that ..
*/
- /* ob= pid->ob; */ /* UNUSED */
cache = pid->cache;
if (timescale) {
@@ -4119,7 +4119,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
G.is_break = false;
/* set caches to baking mode and figure out start frame */
- if (pid->ob) {
+ if (pid->owner_id) {
/* cache/bake a single object */
cache = pid->cache;
if ((cache->flag & PTCACHE_BAKED) == 0) {
@@ -4136,7 +4136,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* get all pids from the object and search for smoke low res */
ListBase pidlist2;
PTCacheID *pid2;
- BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
+ BLI_assert(GS(pid->owner_id->name) == ID_OB);
+ BKE_ptcache_ids_from_object(&pidlist2, (Object *)pid->owner_id, scene, MAX_DUPLI_RECUR);
for (pid2 = pidlist2.first; pid2; pid2 = pid2->next) {
if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
@@ -4425,7 +4426,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
if (cache->index) {
- BKE_object_delete_ptcache(pid->ob, cache->index);
+ BKE_object_delete_ptcache((Object *)pid->owner_id, cache->index);
cache->index = -1;
}
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index c9911d2cf85..4752782eaeb 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1348,9 +1348,10 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio
/* ************************************** */
/* Utilities API */
-/* Get RigidBody world for the given scene, creating one if needed
+/**
+ * Get RigidBody world for the given scene, creating one if needed
*
- * \param scene: Scene to find active Rigid Body world for
+ * \param scene: Scene to find active Rigid Body world for.
*/
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
@@ -1646,7 +1647,7 @@ static void rigidbody_update_sim_ob(
/* Calculate net force of effectors, and apply to sim object:
* - we use 'central force' since apply force requires a "relative position"
* which we don't have... */
- BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
if (G.f & G_DEBUG) {
printf("\tapplying force (%f,%f,%f) to '%s'\n",
eff_force[0],
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 7cf424f53e0..b0faa555f29 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -822,48 +822,70 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
return sce_copy;
}
else {
- BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS);
+ const eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT;
+
+ BKE_id_copy(bmain, (ID *)sce, (ID **)&sce_copy);
id_us_min(&sce_copy->id);
id_us_ensure_real(&sce_copy->id);
+ if (duplicate_flags & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, &sce_copy->id, true);
+ }
+
/* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks. */
if (type == SCE_COPY_FULL) {
+ /* Scene duplication is always root of duplication currently. */
+ const bool is_subprocess = false;
+
+ if (!is_subprocess) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+ }
+
/* Copy Freestyle LineStyle datablocks. */
LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
LISTBASE_FOREACH (
FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
- if (lineset->linestyle) {
- if (is_scene_liboverride && ID_IS_LINKED(lineset->linestyle)) {
- continue;
- }
- id_us_min(&lineset->linestyle->id);
- BKE_id_copy_ex(
- bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, LIB_ID_COPY_ACTIONS);
- }
+ BKE_id_copy_for_duplicate(
+ bmain, &lineset->linestyle->id, is_scene_liboverride, duplicate_flags);
}
}
/* Full copy of world (included animations) */
- if (sce_copy->world) {
- if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->world)) {
- id_us_min(&sce_copy->world->id);
- BKE_id_copy_ex(
- bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS);
- }
- }
+ BKE_id_copy_for_duplicate(bmain, &sce->world->id, is_scene_liboverride, duplicate_flags);
/* Full copy of GreasePencil. */
- if (sce_copy->gpd) {
- if (!is_scene_liboverride || !ID_IS_LINKED(sce_copy->gpd)) {
- id_us_min(&sce_copy->gpd->id);
- BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, LIB_ID_COPY_ACTIONS);
- }
- }
+ BKE_id_copy_for_duplicate(bmain, &sce->gpd->id, is_scene_liboverride, duplicate_flags);
/* Deep-duplicate collections and objects (using preferences' settings for which sub-data to
* duplicate along the object itself). */
- BKE_collection_duplicate(bmain, NULL, sce_copy->master_collection, true, true, true);
+ BKE_collection_duplicate(bmain,
+ NULL,
+ sce_copy->master_collection,
+ duplicate_flags,
+ LIB_ID_DUPLICATE_IS_SUBPROCESS);
+
+ if (!is_subprocess) {
+ /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW.*/
+ BKE_libblock_relink_to_newid(&sce_copy->id);
+
+#ifndef NDEBUG
+ /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those
+ * flags. */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ BLI_assert((id_iter->tag & LIB_TAG_NEW) == 0);
+ }
+ FOREACH_MAIN_ID_END;
+#endif
+
+ /* Cleanup. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+
+ BKE_main_collection_sync(bmain);
+ }
}
else {
/* Remove sequencer if not full copy */
@@ -2271,7 +2293,8 @@ static char *scene_undo_depsgraph_gen_key(Scene *scene, ViewLayer *view_layer, c
size_t key_full_offset = BLI_strncpy_rlen(key_full, scene->id.name, MAX_ID_NAME);
if (scene->id.lib != NULL) {
- key_full_offset += BLI_strncpy_rlen(key_full + key_full_offset, scene->id.lib->name, FILE_MAX);
+ key_full_offset += BLI_strncpy_rlen(
+ key_full + key_full_offset, scene->id.lib->filepath, FILE_MAX);
}
key_full_offset += BLI_strncpy_rlen(key_full + key_full_offset, view_layer->name, MAX_NAME);
BLI_assert(key_full_offset < MAX_ID_NAME + FILE_MAX + MAX_NAME);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index bfc0d437994..c510b3a2dfb 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -393,6 +393,7 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
Panel *panel = lb->first;
for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
new_panel->activedata = NULL;
+ new_panel->runtime.custom_data_ptr = NULL;
panel_list_copy(&new_panel->children, &panel->children);
}
}
@@ -575,18 +576,25 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)
region_free_gizmomap_callback = callback;
}
-void BKE_area_region_panels_free(ListBase *lb)
+static void area_region_panels_free_recursive(Panel *panel)
{
- Panel *panel, *panel_next;
- for (panel = lb->first; panel; panel = panel_next) {
- panel_next = panel->next;
- if (panel->activedata) {
- MEM_freeN(panel->activedata);
- }
- BKE_area_region_panels_free(&panel->children);
+ MEM_SAFE_FREE(panel->activedata);
+
+ LISTBASE_FOREACH_MUTABLE (Panel *, child_panel, &panel->children) {
+ area_region_panels_free_recursive(child_panel);
}
- BLI_freelistN(lb);
+ MEM_freeN(panel);
+}
+
+void BKE_area_region_panels_free(ListBase *lb)
+{
+ LISTBASE_FOREACH_MUTABLE (Panel *, panel, lb) {
+ /* Free custom data just for parent panels to avoid a double free. */
+ MEM_SAFE_FREE(panel->runtime.custom_data_ptr);
+ area_region_panels_free_recursive(panel);
+ }
+ BLI_listbase_clear(lb);
}
/* not region itself */
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 9fa43ed0a5f..de233a8d473 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -2810,7 +2810,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
context->rectx,
context->recty,
ibuf1->rect_float,
- ibuf2->rect_float,
+ NULL,
out->rect_float);
}
else {
@@ -2821,7 +2821,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
- (unsigned char *)ibuf2->rect,
+ NULL,
(unsigned char *)out->rect);
}
@@ -3821,7 +3821,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user)
}
char path[FILE_MAX];
- STRNCPY(path, data->text_font->name);
+ STRNCPY(path, data->text_font->filepath);
BLI_assert(BLI_thread_is_main());
BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&data->text_font->id));
@@ -3895,7 +3895,7 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
data->text_blf_id = -1;
if (data->text_font) {
- data->text_blf_id = BLF_load(data->text_font->name);
+ data->text_blf_id = BLF_load(data->text_font->filepath);
}
}
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 75f7ed82165..604cbf476a8 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -1126,3 +1126,5 @@ int BKE_sequence_supports_modifiers(Sequence *seq)
{
return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 90edebfaa97..297d60e5976 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -406,17 +406,18 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
/* check for a data with the same filename */
switch (GS(ID_PT->name)) {
case ID_SO: {
- id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name));
+ id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->filepath, offsetof(bSound, filepath));
if (id_restore == NULL) {
- id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name);
+ id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->filepath);
(ID_PT)->newid = id_restore; /* reuse next time */
}
break;
}
case ID_MC: {
- id_restore = BLI_findstring(lb, ((MovieClip *)ID_PT)->name, offsetof(MovieClip, name));
+ id_restore = BLI_findstring(
+ lb, ((MovieClip *)ID_PT)->filepath, offsetof(MovieClip, filepath));
if (id_restore == NULL) {
- id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->name);
+ id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->filepath);
(ID_PT)->newid = id_restore; /* reuse next time */
}
break;
@@ -842,30 +843,22 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
/* effects and meta: automatic start and end */
-
if (seq->type & SEQ_TYPE_EFFECT) {
- /* pointers */
- if (seq->seq2 == NULL) {
- seq->seq2 = seq->seq1;
- }
- if (seq->seq3 == NULL) {
- seq->seq3 = seq->seq1;
- }
-
- /* effecten go from seq1 -> seq2: test */
-
- /* we take the largest start and smallest end */
-
- // seq->start = seq->startdisp = MAX2(seq->seq1->startdisp, seq->seq2->startdisp);
- // seq->enddisp = MIN2(seq->seq1->enddisp, seq->seq2->enddisp);
-
if (seq->seq1) {
- /* XXX These resets should not be necessary, but users used to be able to
- * edit effect's length, leading to strange results. See [#29190] */
seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
- seq->start = seq->startdisp = max_iii(
- seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
- seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+ if (seq->seq3) {
+ seq->start = seq->startdisp = max_iii(
+ seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
+ seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+ }
+ else if (seq->seq2) {
+ seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
+ seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
+ }
+ else {
+ seq->start = seq->startdisp = seq->seq1->startdisp;
+ seq->enddisp = seq->seq1->enddisp;
+ }
/* we cant help if strips don't overlap, it wont give useful results.
* but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
if (seq->enddisp < seq->startdisp) {
@@ -919,6 +912,7 @@ static void seq_multiview_name(Scene *scene,
size_t r_size)
{
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_assert(ext != NULL && suffix != NULL && prefix != NULL);
BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
}
@@ -1188,7 +1182,7 @@ static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
Sequence *seq;
for (seq = seqbasep->first; seq; seq = seq->next) {
if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
- /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for prefix */
+ /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */
BLI_snprintf(sui->name_dest,
sizeof(sui->name_dest),
"%.*s.%03d",
@@ -1783,6 +1777,33 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
}
+static bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_id)
+{
+ char fname[FILE_MAXFILE];
+ char suffix[24];
+ StripProxy *proxy = seq->strip->proxy;
+
+ if (proxy == NULL) {
+ return false;
+ }
+
+ BLI_join_dirfile(fname, PROXY_MAXFILE, proxy->dir, proxy->file);
+ BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
+
+ if (view_id > 0) {
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
+ /* TODO(sergey): This will actually append suffix after extension
+ * which is weird but how was originally coded in multiview branch.
+ */
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
+ }
+ else {
+ BLI_strncpy(name, fname, PROXY_MAXFILE);
+ }
+
+ return true;
+}
+
static bool seq_proxy_get_fname(Editing *ed,
Sequence *seq,
int cfra,
@@ -1790,141 +1811,82 @@ static bool seq_proxy_get_fname(Editing *ed,
char *name,
const int view_id)
{
- int frameno;
char dir[PROXY_MAXFILE];
- StripAnim *sanim;
char suffix[24] = {'\0'};
-
StripProxy *proxy = seq->strip->proxy;
- if (!proxy) {
+
+ if (proxy == NULL) {
return false;
}
- /* MOVIE tracks (only exception: custom files) are now handled
- * internally by ImBuf module for various reasons: proper time code
- * support, quicker index build, using one file instead
- * of a full directory of jpeg files, etc. Trying to support old
- * and new method at once could lead to funny effects, if people
- * have both, a directory full of jpeg files and proxy avis, so
- * sorry folks, please rebuild your proxies... */
+ /* Multiview suffix. */
+ if (view_id > 0) {
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
+ }
- sanim = BLI_findlink(&seq->anims, view_id);
+ /* Per strip with Custom file situation is handled separately. */
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
+ ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (seq_proxy_get_custom_file_fname(seq, name, view_id)) {
+ return true;
+ }
+ }
if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
- char fname[FILE_MAXFILE];
+ /* Per project default. */
if (ed->proxy_dir[0] == 0) {
BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
}
- else {
+ else { /* Per project with custom dir. */
BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
}
-
- if (sanim && sanim->anim) {
- IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
- fname[0] = 0;
- }
- else {
- /* We could make a name here, except non-movie's don't generate proxies,
- * cancel until other types of sequence strips are supported. */
- return false;
- }
- BLI_path_append(dir, sizeof(dir), fname);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
}
- else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) &&
- (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
- char fname[FILE_MAXFILE];
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
- BLI_path_append(dir, sizeof(dir), fname);
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
+ else {
+ /* Pre strip with custom dir. */
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
- else {
+ else { /* Per strip default. */
BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
}
}
- else {
- return false;
- }
-
- if (view_id > 0) {
- BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
- }
-
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
- ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) {
- char fname[FILE_MAXFILE];
- BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
- BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
- if (suffix[0] != '\0') {
- /* TODO(sergey): This will actually append suffix after extension
- * which is weird but how was originally coded in multiview branch.
- */
- BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
- }
- else {
- BLI_strncpy(name, fname, PROXY_MAXFILE);
- }
-
- return true;
- }
-
- /* generate a separate proxy directory for each preview size */
+ /* Proxy size number to be used in path. */
int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100;
- if (seq->type == SEQ_TYPE_IMAGE) {
- BLI_snprintf(name,
- PROXY_MAXFILE,
- "%s/images/%d/%s_proxy%s",
- dir,
- proxy_size_number,
- BKE_sequencer_give_stripelem(seq, cfra)->name,
- suffix);
- frameno = 1;
- }
- else {
- frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix);
- }
-
+ BLI_snprintf(name,
+ PROXY_MAXFILE,
+ "%s/images/%d/%s_proxy%s",
+ dir,
+ proxy_size_number,
+ BKE_sequencer_give_stripelem(seq, cfra)->name,
+ suffix);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- BLI_path_frame(name, frameno, 0);
-
strcat(name, ".jpg");
return true;
}
+static bool seq_can_use_proxy(Sequence *seq, IMB_Proxy_Size psize)
+{
+ if (seq->strip->proxy == NULL) {
+ return false;
+ }
+ short size_flags = seq->strip->proxy->build_size_flags;
+ return (seq->flag & SEQ_USE_PROXY) != 0 && psize != IMB_PROXY_NONE && (size_flags & psize) != 0;
+}
+
static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
{
char name[PROXY_MAXFILE];
StripProxy *proxy = seq->strip->proxy;
const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
- const IMB_Proxy_Size psize_flag = seq_rendersize_to_proxysize(psize);
- int size_flags;
Editing *ed = context->scene->ed;
StripAnim *sanim;
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
- }
-
- size_flags = proxy->build_size_flags;
-
/* only use proxies, if they are enabled (even if present!) */
- if (psize_flag == IMB_PROXY_NONE || (size_flags & psize_flag) == 0) {
+ if (!seq_can_use_proxy(seq, seq_rendersize_to_proxysize(psize))) {
return NULL;
}
@@ -2342,7 +2304,9 @@ MINLINE float color_balance_fl(
x = 0.f;
}
- return powf(x, gamma) * mul;
+ x = powf(x, gamma) * mul;
+ CLAMP(x, FLT_MIN, FLT_MAX);
+ return x;
}
static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul)
@@ -2977,9 +2941,9 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
/* Speed effect requires time remapping of cfra for input(s). */
- if (input[1] && seq->type == SEQ_TYPE_SPEED) {
+ if (input[0] && seq->type == SEQ_TYPE_SPEED) {
float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i);
- ibuf[i] = seq_render_strip(context, state, input[i], target_frame);
+ ibuf[i] = seq_render_strip(context, state, input[0], target_frame);
}
else { /* Other effects. */
if (input[i]) {
@@ -2988,7 +2952,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
}
}
- if (ibuf[0] && ibuf[1]) {
+ if (ibuf[0] && (ibuf[1] || BKE_sequence_effect_get_num_inputs(seq->type) == 1)) {
if (sh.multithreaded) {
out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
@@ -3021,97 +2985,126 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
return out;
}
+/* Render individual view for multiview or single (default view) for monoview. */
+static ImBuf *seq_render_image_strip_view(const SeqRenderData *context,
+ Sequence *seq,
+ char *name,
+ char *prefix,
+ const char *ext,
+ int view_id)
+{
+
+ ImBuf *ibuf = NULL;
+
+ int flag = IB_rect | IB_metadata;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL) {
+ flag |= IB_alphamode_premul;
+ }
+
+ if (prefix[0] == '\0') {
+ ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
+ ibuf = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ /* We don't need both (speed reasons)! */
+ if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ /* All sequencer color is done in SRGB space, linear gives odd crossfades. */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ return ibuf;
+}
+
+static bool seq_image_strip_is_multiview_render(
+ Scene *scene, Sequence *seq, int totfiles, char *name, char *r_prefix, const char *r_ext)
+{
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(scene, name, r_prefix, &r_ext);
+ if (r_prefix[0] == '\0') {
+ return false;
+ }
+ }
+ else {
+ r_prefix[0] = '\0';
+ }
+
+ return (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
+}
+
static ImBuf *seq_render_image_strip(const SeqRenderData *context,
Sequence *seq,
float UNUSED(nr),
- float cfra)
+ float cfra,
+ bool *r_is_proxy_image)
{
- ImBuf *ibuf = NULL;
char name[FILE_MAX];
- bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (context->scene->r.scemode & R_MULTIVIEW) != 0;
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- int flag;
+ const char *ext = NULL;
+ char prefix[FILE_MAX];
+ ImBuf *ibuf = NULL;
- if (s_elem) {
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ if (s_elem == NULL) {
+ return NULL;
}
- flag = IB_rect | IB_metadata;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL) {
- flag |= IB_alphamode_premul;
- }
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- if (!s_elem) {
- /* don't do anything */
+ /* Try to get a proxy image. */
+ ibuf = seq_proxy_fetch(context, seq, cfra);
+ if (ibuf != NULL) {
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ *r_is_proxy_image = true;
+ return ibuf;
}
- else if (is_multiview) {
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- int totviews;
- struct ImBuf **ibufs_arr;
- char prefix[FILE_MAX];
- const char *ext = NULL;
- if (totfiles > 1) {
- BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
- if (prefix[0] == '\0') {
- goto monoview_image;
- }
- }
- else {
- prefix[0] = '\0';
- }
+ /* Proxy not found, render original. */
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ bool is_multiview_render = seq_image_strip_is_multiview_render(
+ context->scene, seq, totfiles, name, prefix, ext);
- totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
- ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+ if (is_multiview_render) {
+ int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ImBuf **ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
for (int view_id = 0; view_id < totfiles; view_id++) {
+ ibufs_arr[view_id] = seq_render_image_strip_view(context, seq, name, prefix, ext, view_id);
+ }
- if (prefix[0] == '\0') {
- ibufs_arr[view_id] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
- }
- else {
- char str[FILE_MAX];
- seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
- ibufs_arr[view_id] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
- }
-
- if (ibufs_arr[view_id]) {
- /* we don't need both (speed reasons)! */
- if (ibufs_arr[view_id]->rect_float && ibufs_arr[view_id]->rect) {
- imb_freerectImBuf(ibufs_arr[view_id]);
- }
- }
+ if (ibufs_arr[0] == NULL) {
+ return NULL;
}
- if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0]) {
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
}
for (int view_id = 0; view_id < totviews; view_id++) {
- if (ibufs_arr[view_id]) {
- SeqRenderData localcontext = *context;
- localcontext.view_id = view_id;
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = view_id;
- if (view_id != context->view_id) {
- ibufs_arr[view_id] = seq_render_preprocess_ibuf(
- &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false);
- }
+ if (view_id != context->view_id) {
+ ibufs_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false);
}
}
- /* return the original requested ImBuf */
+ /* Return the original requested ImBuf. */
ibuf = ibufs_arr[context->view_id];
- if (ibuf) {
- s_elem->orig_width = ibufs_arr[0]->x;
- s_elem->orig_height = ibufs_arr[0]->y;
- }
- /* "remove" the others (decrease their refcount) */
+ /* Remove the others (decrease their refcount). */
for (int view_id = 0; view_id < totviews; view_id++) {
if (ibufs_arr[view_id] != ibuf) {
IMB_freeImBuf(ibufs_arr[view_id]);
@@ -3121,116 +3114,114 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
MEM_freeN(ibufs_arr);
}
else {
- monoview_image:
- if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ ibuf = seq_render_image_strip_view(context, seq, name, prefix, ext, context->view_id);
+ }
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- }
+ if (ibuf == NULL) {
+ return NULL;
}
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+
return ibuf;
}
-static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
- Sequence *seq,
- float nr,
- float cfra)
+/**
+ * Render individual view for multi-view or single (default view) for mono-view.
+ */
+static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ StripAnim *sanim,
+ bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
- StripAnim *sanim;
+ IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
- bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (context->scene->r.scemode & R_MULTIVIEW) != 0;
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
+ if (seq_can_use_proxy(seq, psize)) {
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ psize);
+ if (ibuf != NULL) {
+ *r_is_proxy_image = true;
+ }
+ }
- if ((seq->flag & SEQ_USE_PROXY) == 0) {
- psize = IMB_PROXY_NONE;
+ /* Fetching for requested proxy size failed, try fetching the original instead. */
+ if (ibuf == NULL) {
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf == NULL) {
+ return NULL;
}
- /* load all the videos */
- seq_open_anim_file(context->scene, seq, false);
- if (is_multiview) {
- ImBuf **ibuf_arr;
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- int totviews;
- int ibuf_view_id;
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
- if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) {
- goto monoview_movie;
- }
+ /* We don't need both (speed reasons)! */
+ if (ibuf->rect_float != NULL && ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(
+ const SeqRenderData *context, Sequence *seq, float nr, float cfra, bool *r_is_proxy_image)
+{
+ /* Load all the videos. */
+ seq_open_anim_file(context->scene, seq, false);
+
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim = seq->anims.first;
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ bool is_multiview_render = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0 &&
+ BLI_listbase_count_at_most(&seq->anims, totfiles + 1) == totfiles;
- totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ if (is_multiview_render) {
+ ImBuf **ibuf_arr;
+ int totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+ int ibuf_view_id;
for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) {
if (sanim->anim) {
- IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
-
- ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- psize);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf_arr[ibuf_view_id] && psize != IMB_PROXY_NONE) {
- ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf_arr[ibuf_view_id]) {
- /* we don't need both (speed reasons)! */
- if (ibuf_arr[ibuf_view_id]->rect_float && ibuf_arr[ibuf_view_id]->rect) {
- imb_freerectImBuf(ibuf_arr[ibuf_view_id]);
- }
- }
+ ibuf_arr[ibuf_view_id] = seq_render_movie_strip_view(
+ context, seq, nr, sanim, r_is_proxy_image);
}
}
if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
- if (ibuf_arr[0]) {
- IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
- }
- else {
- /* probably proxy hasn't been created yet */
+ if (ibuf_arr[0] == NULL) {
+ /* Probably proxy hasn't been created yet. */
MEM_freeN(ibuf_arr);
return NULL;
}
+
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
}
for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
localcontext.view_id = view_id;
- if (ibuf_arr[view_id]) {
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[view_id], false);
- }
if (view_id != context->view_id) {
ibuf_arr[view_id] = seq_render_preprocess_ibuf(
&localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false, false);
}
}
- /* return the original requested ImBuf */
+ /* Return the original requested ImBuf. */
ibuf = ibuf_arr[context->view_id];
- if (ibuf) {
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- /* "remove" the others (decrease their refcount) */
+ /* Remove the others (decrease their refcount). */
for (int view_id = 0; view_id < totviews; view_id++) {
if (ibuf_arr[view_id] != ibuf) {
IMB_freeImBuf(ibuf_arr[view_id]);
@@ -3240,44 +3231,39 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
MEM_freeN(ibuf_arr);
}
else {
- monoview_movie:
- sanim = seq->anims.first;
- if (sanim && sanim->anim) {
- IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
-
- ibuf = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- psize);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf && psize != IMB_PROXY_NONE) {
- ibuf = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ ibuf = seq_render_movie_strip_view(context, seq, nr, sanim, r_is_proxy_image);
+ }
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
+ if (ibuf == NULL) {
+ return NULL;
+ }
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- }
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+
+ return ibuf;
+}
+
+static ImBuf *seq_get_movieclip_ibuf(Sequence *seq, MovieClipUser user)
+{
+ ImBuf *ibuf = NULL;
+ float tloc[2], tscale, tangle;
+ if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
+ ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
+ }
+ else {
+ ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
}
return ibuf;
}
-static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr)
+static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
MovieClipUser user;
- float tloc[2], tscale, tangle;
IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
if (!seq->clip) {
@@ -3288,8 +3274,6 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence
BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame);
- user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
-
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
switch (psize) {
case IMB_PROXY_NONE:
@@ -3313,11 +3297,17 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence
user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT;
}
- if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
- ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
+ /* Try to get a proxy image. */
+ ibuf = seq_get_movieclip_ibuf(seq, user);
+
+ if (ibuf != NULL && psize != IMB_PROXY_NONE) {
+ *r_is_proxy_image = true;
}
- else {
- ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
+
+ /* If proxy is not found, grab full-size frame. */
+ if (ibuf == NULL) {
+ user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
+ ibuf = seq_get_movieclip_ibuf(seq, user);
}
return ibuf;
@@ -3695,7 +3685,8 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
- float cfra)
+ float cfra,
+ bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
float nr = BKE_sequencer_give_stripelem_index(seq, cfra);
@@ -3747,17 +3738,17 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
}
case SEQ_TYPE_IMAGE: {
- ibuf = seq_render_image_strip(context, seq, nr, cfra);
+ ibuf = seq_render_image_strip(context, seq, nr, cfra, r_is_proxy_image);
break;
}
case SEQ_TYPE_MOVIE: {
- ibuf = seq_render_movie_strip(context, seq, nr, cfra);
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra, r_is_proxy_image);
break;
}
case SEQ_TYPE_MOVIECLIP: {
- ibuf = seq_render_movieclip_strip(context, seq, nr);
+ ibuf = seq_render_movieclip_strip(context, seq, nr, r_is_proxy_image);
if (ibuf) {
/* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */
@@ -3852,40 +3843,26 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
clock_t begin = seq_estimate_render_cost_begin();
ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
+ if (ibuf != NULL) {
+ return ibuf;
+ }
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false);
if (ibuf == NULL) {
- ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW, false);
- if (ibuf == NULL) {
- /* MOVIECLIPs have their own proxy management */
- if (seq->type != SEQ_TYPE_MOVIECLIP) {
- ibuf = seq_proxy_fetch(context, seq, cfra);
- is_proxy_image = (ibuf != NULL);
- }
-
- if (ibuf == NULL) {
- ibuf = do_render_strip_uncached(context, state, seq, cfra);
- }
-
- if (ibuf) {
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- is_proxy_image = seq_rendersize_to_proxysize(context->preview_render_size) !=
- IMB_PROXY_NONE;
- }
- }
- }
-
- if (ibuf) {
- use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- }
-
- if (ibuf == NULL) {
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
+ ibuf = do_render_strip_uncached(context, state, seq, cfra, &is_proxy_image);
+ }
+ if (ibuf) {
+ use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
ibuf = seq_render_preprocess_ibuf(
context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image, is_preprocessed);
}
+
+ if (ibuf == NULL) {
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+ }
+
return ibuf;
}
@@ -5052,7 +5029,7 @@ int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
return 1;
}
-/* prefix + [" + escaped_name + "] + \0 */
+/* r_prefix + [" + escaped_name + "] + \0 */
#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 0ad61de1ff2..2923298c5d5 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -82,8 +82,9 @@ ShaderFxData *BKE_shaderfx_new(int type)
BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
fx->type = type;
- fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render;
fx->flag = eShaderFxFlag_OverrideLibrary_Local;
+ fx->ui_expand_flag = 1; /* Expand only the parent panel by default. */
if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode) {
fx->mode |= eShaderFxMode_Editmode;
@@ -156,7 +157,7 @@ bool BKE_shaderfx_depends_ontime(ShaderFxData *fx)
const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
{
/* type unsigned, no need to check < 0 */
- if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ if (type < NUM_SHADER_FX_TYPES && type > 0 && shader_fx_types[type]->name[0] != '\0') {
return shader_fx_types[type];
}
else {
@@ -164,6 +165,20 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
}
}
+/**
+ * Get an effect's panel type, which was defined in the #panelRegister callback.
+ *
+ * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
+ * the defined prefix.
+ */
+void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
+
+ strcpy(r_idname, SHADERFX_TYPE_PANEL_PREFIX);
+ strcat(r_idname, fxi->name);
+}
+
void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
{
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type);
@@ -198,6 +213,7 @@ void BKE_shaderfx_copydata_ex(ShaderFxData *fx, ShaderFxData *target, const int
target->mode = fx->mode;
target->flag = fx->flag;
+ target->ui_expand_flag = fx->ui_expand_flag;
if (fxi->copyData) {
fxi->copyData(fx, target);
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 20a23ab8b38..eef848aff72 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -54,10 +54,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-using blender::float3;
-using blender::MutableSpan;
-using blender::Span;
-
static void simulation_init_data(ID *id)
{
Simulation *simulation = (Simulation *)id;
@@ -168,6 +164,9 @@ void *BKE_simulation_add(Main *bmain, const char *name)
return simulation;
}
+namespace blender {
+namespace bke {
+
static MutableSpan<float3> get_particle_positions(ParticleSimulationState *state)
{
return MutableSpan<float3>(
@@ -197,7 +196,7 @@ static void copy_particle_state_to_cow(ParticleSimulationState *state_orig,
state_cow->tot_particles = state_orig->tot_particles;
}
-void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation)
+static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation)
{
int current_frame = scene->r.cfra;
@@ -259,3 +258,11 @@ void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *
copy_particle_state_to_cow(state_orig, state_cow);
}
}
+
+} // namespace bke
+} // namespace blender
+
+void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation)
+{
+ blender::bke::simulation_data_update(depsgraph, scene, simulation);
+}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 68d0822a223..9c7abbdf876 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1479,7 +1479,8 @@ static void _scan_for_ext_spring_forces(
mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
pd_point_from_soft(scene, pos, vel, -1, &epoint);
- BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(
+ effectors, NULL, sb->effector_weights, &epoint, force, NULL, speed);
mul_v3_fl(speed, windfactor);
add_v3_v3(vel, speed);
@@ -2107,7 +2108,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene,
float eval_sb_fric_force_scale = sb_fric_force_scale(ob);
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint - bp, &epoint);
- BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, NULL, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor * eval_sb_fric_force_scale);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index e8f31594cc0..a293bc55073 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -172,7 +172,7 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
BLI_path_abs(str, path);
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
- BLI_strncpy(sound->name, filepath, FILE_MAX);
+ BLI_strncpy(sound->filepath, filepath, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
@@ -193,7 +193,7 @@ bSound *BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_
/* first search an identical filepath */
for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
- BLI_strncpy(strtest, sound->name, sizeof(sound->name));
+ BLI_strncpy(strtest, sound->filepath, sizeof(sound->filepath));
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
if (BLI_path_cmp(strtest, str) == 0) {
@@ -452,8 +452,8 @@ static void sound_load_audio(Main *bmain, bSound *sound, bool free_waveform)
/* load sound */
PackedFile *pf = sound->packedfile;
- /* don't modify soundact->sound->name, only change a copy */
- BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
+ /* don't modify soundact->sound->filepath, only change a copy */
+ BLI_strncpy(fullpath, sound->filepath, sizeof(fullpath));
BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
/* but we need a packed file then */
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 4892e8d6ede..8455b60c894 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1426,9 +1426,9 @@ void BKE_studiolight_init(void)
BLI_addtail(&studiolights, sl);
- /* go over the preset folder and add a studiolight for every image with its path */
- /* for portable installs (where USER and SYSTEM paths are the same),
- * only go over LOCAL datafiles once */
+ /* Go over the preset folder and add a studio-light for every image with its path. */
+ /* For portable installs (where USER and SYSTEM paths are the same),
+ * only go over LOCAL data-files once. */
/* Also reserve icon space for it. */
if (!BKE_appdir_app_is_portable_install()) {
studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index d5d5530c1ce..a1e218390c3 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -655,6 +655,7 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
MEM_SAFE_FREE(adjacent_vertex->corner_coords);
}
MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
+ MEM_SAFE_FREE(subdiv_ccg->cache_.start_face_grid_index);
MEM_freeN(subdiv_ccg);
}
@@ -1797,13 +1798,40 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index)
{
- // Subdiv *subdiv = subdiv_ccg->subdiv; /* UNUSED */
- // OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; /* UNUSED */
- SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index];
-
- // const int face_grid_index = grid_index - face->start_grid_index; /* UNUSED */
+ const SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index];
const int face_index = face - subdiv_ccg->faces;
return face_index;
}
+const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg)
+{
+ if (subdiv_ccg->cache_.start_face_grid_index == NULL) {
+ const Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ if (topology_refiner == NULL) {
+ return NULL;
+ }
+
+ const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
+
+ subdiv_ccg->cache_.start_face_grid_index = MEM_malloc_arrayN(
+ sizeof(int), num_coarse_faces, "start_face_grid_index");
+
+ int start_grid_index = 0;
+ for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
+ const int num_face_grids = topology_refiner->getNumFaceVertices(topology_refiner,
+ face_index);
+ subdiv_ccg->cache_.start_face_grid_index[face_index] = start_grid_index;
+ start_grid_index += num_face_grids;
+ }
+ }
+
+ return subdiv_ccg->cache_.start_face_grid_index;
+}
+
+const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg)
+{
+ return subdiv_ccg->cache_.start_face_grid_index;
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index bce2266f3e9..5f85e1a1664 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -59,34 +59,6 @@
# include "BPY_extern.h"
#endif
-/*
- * How Texts should work
- * --
- * A text should relate to a file as follows -
- * (Text *)->name should be the place where the
- * file will or has been saved.
- *
- * (Text *)->flags has the following bits
- * TXT_ISDIRTY - should always be set if the file in mem. differs from
- * the file on disk, or if there is no file on disk.
- * TXT_ISMEM - should always be set if the Text has not been mapped to
- * a file, in which case (Text *)->name may be NULL or garbage.
- * TXT_ISEXT - should always be set if the Text is not to be written into
- * the .blend
- * TXT_ISSCRIPT - should be set if the user has designated the text
- * as a script. (NEW: this was unused, but now it is needed by
- * space handler script links (see header_view3d.c, for example)
- *
- * ->>> see also: /makesdna/DNA_text_types.h
- *
- * Display
- * --
- *
- * The st->top determines at what line the top of the text is displayed.
- * If the user moves the cursor the st containing that cursor should
- * be popped ... other st's retain their own top location.
- */
-
/* -------------------------------------------------------------------- */
/** \name Prototypes
* \{ */
@@ -110,9 +82,8 @@ static void text_init_data(ID *id)
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(text, id));
- text->name = NULL;
+ text->filepath = NULL;
- text->nlines = 1;
text->flags = TXT_ISDIRTY | TXT_ISMEM;
if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0) {
text->flags |= TXT_TABSTOSPACES;
@@ -157,8 +128,8 @@ static void text_copy_data(Main *UNUSED(bmain),
const Text *text_src = (Text *)id_src;
/* File name can be NULL. */
- if (text_src->name) {
- text_dst->name = BLI_strdup(text_src->name);
+ if (text_src->filepath) {
+ text_dst->filepath = BLI_strdup(text_src->filepath);
}
text_dst->flags |= TXT_ISDIRTY;
@@ -190,7 +161,7 @@ static void text_free_data(ID *id)
BKE_text_free_lines(text);
- MEM_SAFE_FREE(text->name);
+ MEM_SAFE_FREE(text->filepath);
#ifdef WITH_PYTHON
BPY_text_free_code(text);
#endif
@@ -316,12 +287,12 @@ static void cleanup_textline(TextLine *tl)
*/
static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
{
- int i, llen;
+ int i, llen, lines_count;
BLI_assert(BLI_listbase_is_empty(&text->lines));
- text->nlines = 0;
llen = 0;
+ lines_count = 0;
for (i = 0; i < len; i++) {
if (buffer[i] == '\n') {
TextLine *tmp;
@@ -339,7 +310,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
cleanup_textline(tmp);
BLI_addtail(&text->lines, tmp);
- text->nlines++;
+ lines_count += 1;
llen = 0;
continue;
@@ -353,7 +324,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
* - file is empty. in this case new line is needed to start editing from.
* - last character in buffer is \n. in this case new line is needed to
* deal with newline at end of file. (see [#28087]) (sergey) */
- if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') {
+ if (llen != 0 || lines_count == 0 || buffer[len - 1] == '\n') {
TextLine *tmp;
tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
@@ -370,7 +341,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
cleanup_textline(tmp);
BLI_addtail(&text->lines, tmp);
- text->nlines++;
+ /* lines_count += 1; */ /* UNUSED */
}
text->curl = text->sell = text->lines.first;
@@ -384,11 +355,11 @@ bool BKE_text_reload(Text *text)
char filepath_abs[FILE_MAX];
BLI_stat_t st;
- if (!text->name) {
+ if (!text->filepath) {
return false;
}
- BLI_strncpy(filepath_abs, text->name, FILE_MAX);
+ BLI_strncpy(filepath_abs, text->filepath, FILE_MAX);
BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
@@ -444,8 +415,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
}
if (is_internal == false) {
- ta->name = MEM_mallocN(strlen(file) + 1, "text_name");
- strcpy(ta->name, file);
+ ta->filepath = MEM_mallocN(strlen(file) + 1, "text_name");
+ strcpy(ta->filepath, file);
}
else {
ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
@@ -503,11 +474,11 @@ int BKE_text_file_modified_check(Text *text)
int result;
char file[FILE_MAX];
- if (!text->name) {
+ if (!text->filepath) {
return 0;
}
- BLI_strncpy(file, text->name, FILE_MAX);
+ BLI_strncpy(file, text->filepath, FILE_MAX);
BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
if (!BLI_exists(file)) {
@@ -537,11 +508,11 @@ void BKE_text_file_modified_ignore(Text *text)
int result;
char file[FILE_MAX];
- if (!text->name) {
+ if (!text->filepath) {
return;
}
- BLI_strncpy(file, text->name, FILE_MAX);
+ BLI_strncpy(file, text->filepath, FILE_MAX);
BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
if (!BLI_exists(file)) {
@@ -738,6 +709,10 @@ bool txt_cursor_is_line_end(Text *text)
/* -------------------------------------------------------------------- */
/** \name Cursor Movement Functions
+ *
+ * \note If the user moves the cursor the space containing that cursor should be popped
+ * See #txt_pop_first, #txt_pop_last
+ * Other space-types retain their own top location.
* \{ */
void txt_move_up(Text *text, const bool sel)
@@ -1309,6 +1284,8 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
text->selc = BLI_str_utf8_offset_from_index(tol->line, endc);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Buffer Conversion for Undo/Redo
*
@@ -2105,8 +2082,6 @@ static void txt_select_prefix(Text *text, const char *add, bool skip_blank_lines
/**
* Generic un-prefix operation, use for comment & indent.
*
- * \param r_line_index_mask: List of lines that are already at indent level 0,
- * to store them later into the undo buffer.
* \param require_all: When true, all non-empty lines must have this prefix.
* Needed for comments where we might want to un-comment a block which contains some comments.
*