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
path: root/source
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2016-11-16 18:36:43 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-11-16 18:36:43 +0300
commitd30baf60c662915772e7952c1b715c461cb979ff (patch)
tree86555e1cc531f988bc6820c451676d59148dc8a7 /source
parentd3947aef590e5f3a7baad48d3957d640a2be946a (diff)
parent2a2eb0c463bd96d42f7306eb17f88cad87f73aea (diff)
Merge branch 'master' into openvdb
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h8
-rw-r--r--source/blender/blenkernel/BKE_library_query.h3
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h2
-rw-r--r--source/blender/blenkernel/intern/action.c4
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c11
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c4
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c7
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/cachefile.c4
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4
-rw-r--r--source/blender/blenkernel/intern/library.c248
-rw-r--r--source/blender/blenkernel/intern/library_query.c40
-rw-r--r--source/blender/blenkernel/intern/library_remap.c47
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c5
-rw-r--r--source/blender/blenkernel/intern/object_deform.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c17
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c36
-rw-r--r--source/blender/blenkernel/intern/smoke.c11
-rw-r--r--source/blender/blenkernel/intern/sound.c3
-rw-r--r--source/blender/blenlib/intern/task.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/blenloader/intern/versioning_270.c29
-rw-r--r--source/blender/blenloader/intern/writefile.c4
-rw-r--r--source/blender/bmesh/bmesh_class.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c265
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c107
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c75
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c114
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h6
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c6
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c12
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c2
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c3
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c10
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c2
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/collada/MeshImporter.cpp15
-rw-r--r--source/blender/collada/TransformWriter.cpp5
-rw-r--r--source/blender/collada/collada.h3
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt1
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h102
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc53
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc35
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc360
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h28
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc92
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h128
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc211
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc13
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h18
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc57
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc19
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.h4
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc30
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h32
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc81
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h50
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc2
-rw-r--r--source/blender/editors/animation/anim_ops.c4
-rw-r--r--source/blender/editors/armature/armature_edit.c1
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c23
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c9
-rw-r--r--source/blender/editors/interface/interface_handlers.c56
-rw-r--r--source/blender/editors/interface/interface_icons.c233
-rw-r--r--source/blender/editors/interface/resources.c14
-rw-r--r--source/blender/editors/io/io_collada.c1
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c12
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c4
-rw-r--r--source/blender/editors/object/object_add.c17
-rw-r--r--source/blender/editors/object/object_relations.c16
-rw-r--r--source/blender/editors/object/object_vgroup.c5
-rw-r--r--source/blender/editors/render/render_opengl.c35
-rw-r--r--source/blender/editors/screen/screen_ops.c23
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c9
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c187
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h6
-rw-r--r--source/blender/editors/transform/transform.c4
-rw-r--r--source/blender/editors/transform/transform_conversions.c4
-rw-r--r--source/blender/editors/util/undo.c23
-rw-r--r--source/blender/gpu/GPU_shader.h1
-rw-r--r--source/blender/gpu/intern/gpu_shader.c13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl12
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp11
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h12
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h23
-rw-r--r--source/blender/makesrna/intern/rna_ID.c26
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c54
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c142
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c56
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c107
-rw-r--r--source/blender/makesrna/intern/rna_wm.c46
-rw-r--r--source/blender/modifiers/intern/MOD_array.c8
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c5
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c5
-rw-r--r--source/blender/python/intern/bpy_library_load.c7
-rw-r--r--source/blender/render/intern/source/shadeoutput.c10
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c12
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c4
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c5
-rw-r--r--source/creator/CMakeLists.txt58
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp4
134 files changed, 2414 insertions, 1482 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index c2323100205..78d6f6c7cb9 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -97,6 +97,7 @@ void BKE_armature_where_is(struct bArmature *arm);
void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion);
void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm);
+void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones);
void BKE_pose_where_is(struct Scene *scene, struct Object *ob);
void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 9547eeb9838..84a6d07be7d 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -42,6 +42,7 @@ extern bool BKE_undo_is_valid(const char *name);
extern void BKE_undo_reset(void);
extern void BKE_undo_number(struct bContext *C, int nr);
extern const char *BKE_undo_get_name(int nr, bool *r_active);
+extern const char *BKE_undo_get_name_last(void);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 55142510f9e..baf8510dd0d 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 278
-#define BLENDER_SUBVERSION 1
+#define BLENDER_SUBVERSION 3
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 0d82de09165..855eb10976c 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -39,6 +39,7 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct BlendThumbnail;
+struct GHash;
struct ListBase;
struct ID;
struct ImBuf;
@@ -64,7 +65,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
/* library_remap.c (keep here since they're general functions) */
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
@@ -125,8 +126,11 @@ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
void BKE_library_free(struct Library *lib);
void BKE_library_make_local(
- struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
+ struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids,
+ const bool untagged_only, const bool set_fake);
+void BKE_id_tag_set_atomic(struct ID *id, int tag);
+void BKE_id_tag_clear_atomic(struct ID *id, int tag);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index c6b63754b57..a7470107c24 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -88,6 +88,7 @@ bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
-void BKE_library_tag_unused_linked_data(struct Main *bmain, const bool do_init_tag);
+void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index a0a885c2a04..19a2220006a 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -51,9 +51,11 @@ bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const
bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection);
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
void BKE_object_defgroup_remove_all(struct Object *ob);
+
/* Select helpers */
enum eVGroupSelect;
bool *BKE_object_defgroup_subset_from_select_type(
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 470098f8c7c..dcbb667adca 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -433,8 +433,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->scaleIn = chan->scaleOut = 1.0f;
- chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
- chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
+ chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
+ chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
chan->ikrotweight = chan->iklinweight = 0.0f;
unit_m4(chan->constinv);
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index e3764adb969..a5abc6beff8 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1657,7 +1657,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* for cases like duplifarmes it's only a temporary so don't
* notify anyone of updates */
if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
+ BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC);
DAG_id_type_tag(G.main, GS(id->name));
}
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index c644fe09364..2b333941c6e 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1794,6 +1794,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* copy posechannel to temp, but restore important pointers */
pchanw = *pchanp;
+ pchanw.bone = pchan->bone;
pchanw.prev = pchan->prev;
pchanw.next = pchan->next;
pchanw.parent = pchan->parent;
@@ -1916,7 +1917,7 @@ void BKE_pose_clear_pointers(bPose *pose)
/* only after leave editmode, duplicating, validating older files, library syncing */
/* NOTE: pose->flag is set for it */
-void BKE_pose_rebuild(Object *ob, bArmature *arm)
+void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
{
Bone *bone;
bPose *pose;
@@ -1963,8 +1964,9 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
#ifdef WITH_LEGACY_DEPSGRAPH
/* the sorting */
/* Sorting for new dependnecy graph is done on the scene graph level. */
- if (counter > 1)
+ if (counter > 1 && sort_bones) {
DAG_pose_sort(ob);
+ }
#endif
ob->pose->flag &= ~POSE_RECALC;
@@ -1973,6 +1975,11 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_channels_hash_make(ob->pose);
}
+void BKE_pose_rebuild(Object *ob, bArmature *arm)
+{
+ BKE_pose_rebuild_ex(ob, arm, true);
+}
+
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index a4c28121040..e57524af546 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -101,7 +101,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor
IMB_colormanagement_check_file_config(bmain_dst);
/* Append, rather than linking. */
Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain_dst, lib, true, false);
+ 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.
*/
@@ -150,7 +150,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
/* append, rather than linking */
lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, true, false);
+ BKE_library_make_local(bmain, lib, NULL, true, false);
/* important we unset, otherwise these object wont
* link into other scenes from this blend file */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index d64bf7ecf43..ce6d29bbfee 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
return NULL;
}
+/* return the name of the last item */
+const char *BKE_undo_get_name_last()
+{
+ UndoElem *uel = undobase.last;
+ return (uel ? uel->name : NULL);
+}
+
/**
* Saves .blend using undo buffer.
*
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6da68470ecc..54f709a1e5b 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -407,9 +407,9 @@ bool BKE_blendfile_read_from_memfile(
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true);
while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true);
setup_app_data(C, bfd, "<memory1>", reports);
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 6a08673144e..deeb35bd880 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -93,7 +93,9 @@ void BKE_cachefile_free(CacheFile *cache_file)
ABC_free_handle(cache_file->handle);
#endif
- BLI_mutex_free(cache_file->handle_mutex);
+ if (cache_file->handle_mutex) {
+ BLI_mutex_free(cache_file->handle_mutex);
+ }
BLI_freelistN(&cache_file->object_paths);
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 02ae123a71e..50f8423bbff 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -3284,7 +3284,7 @@ void DAG_threaded_update_handle_node_updated(void *node_v,
for (itA = node->child; itA; itA = itA->next) {
DagNode *child_node = itA->node;
if (child_node != node) {
- atomic_sub_uint32(&child_node->num_pending_parents, 1);
+ atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1);
if (child_node->num_pending_parents == 0) {
bool need_schedule;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index c7399047ed5..66070923153 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2264,7 +2264,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
* to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
*/
tPoint->neighbour_pixel = ind - 1;
- atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
tPoint->tri_index = i;
/* Now calculate pixel data for this pixel as it was on polygon surface */
@@ -2289,7 +2289,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
/* Increase the final number of active surface points if relevant. */
if (tPoint->tri_index != -1)
- atomic_add_uint32(active_points, 1);
+ atomic_add_and_fetch_uint32(active_points, 1);
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 14612151a8e..3411eae22e1 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -73,6 +73,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
@@ -128,6 +129,8 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "atomic_ops.h"
+
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -261,9 +264,12 @@ void id_fake_user_clear(ID *id)
}
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
{
- if (*id_pointer) {
+ /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
+ * Just skip it, shape key can only be either indirectly linked, or fully local, period.
+ * And let's curse one more time that stupid useless shapekey ID type! */
+ if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
id_lib_extern(*id_pointer);
}
@@ -1205,46 +1211,46 @@ void BKE_main_free(Main *mainvar)
while ( (id = lb->first) ) {
#if 1
- BKE_libblock_free_ex(mainvar, id, false);
+ BKE_libblock_free_ex(mainvar, id, false, false);
#else
/* errors freeing ID's can be hard to track down,
* enable this so valgrind will give the line number in its error log */
switch (a) {
- case 0: BKE_libblock_free_ex(mainvar, id, false); break;
- case 1: BKE_libblock_free_ex(mainvar, id, false); break;
- case 2: BKE_libblock_free_ex(mainvar, id, false); break;
- case 3: BKE_libblock_free_ex(mainvar, id, false); break;
- case 4: BKE_libblock_free_ex(mainvar, id, false); break;
- case 5: BKE_libblock_free_ex(mainvar, id, false); break;
- case 6: BKE_libblock_free_ex(mainvar, id, false); break;
- case 7: BKE_libblock_free_ex(mainvar, id, false); break;
- case 8: BKE_libblock_free_ex(mainvar, id, false); break;
- case 9: BKE_libblock_free_ex(mainvar, id, false); break;
- case 10: BKE_libblock_free_ex(mainvar, id, false); break;
- case 11: BKE_libblock_free_ex(mainvar, id, false); break;
- case 12: BKE_libblock_free_ex(mainvar, id, false); break;
- case 13: BKE_libblock_free_ex(mainvar, id, false); break;
- case 14: BKE_libblock_free_ex(mainvar, id, false); break;
- case 15: BKE_libblock_free_ex(mainvar, id, false); break;
- case 16: BKE_libblock_free_ex(mainvar, id, false); break;
- case 17: BKE_libblock_free_ex(mainvar, id, false); break;
- case 18: BKE_libblock_free_ex(mainvar, id, false); break;
- case 19: BKE_libblock_free_ex(mainvar, id, false); break;
- case 20: BKE_libblock_free_ex(mainvar, id, false); break;
- case 21: BKE_libblock_free_ex(mainvar, id, false); break;
- case 22: BKE_libblock_free_ex(mainvar, id, false); break;
- case 23: BKE_libblock_free_ex(mainvar, id, false); break;
- case 24: BKE_libblock_free_ex(mainvar, id, false); break;
- case 25: BKE_libblock_free_ex(mainvar, id, false); break;
- case 26: BKE_libblock_free_ex(mainvar, id, false); break;
- case 27: BKE_libblock_free_ex(mainvar, id, false); break;
- case 28: BKE_libblock_free_ex(mainvar, id, false); break;
- case 29: BKE_libblock_free_ex(mainvar, id, false); break;
- case 30: BKE_libblock_free_ex(mainvar, id, false); break;
- case 31: BKE_libblock_free_ex(mainvar, id, false); break;
- case 32: BKE_libblock_free_ex(mainvar, id, false); break;
- case 33: BKE_libblock_free_ex(mainvar, id, false); break;
- case 34: BKE_libblock_free_ex(mainvar, id, false); break;
+ case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
default:
BLI_assert(0);
break;
@@ -1626,30 +1632,28 @@ void BKE_main_id_clear_newpoins(Main *bmain)
* \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
* \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
*/
-/* XXX TODO This function should probably be reworked.
- *
- * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
+/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
* they were also indirectly used or not...
*
- * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up
+ * Current version uses regular id_make_local callback, which is not super-efficient since this ends up
* duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
*
- * We could first check all IDs and detect those to be made local that are only used by other local or future-local
- * datablocks, and directly tag those as local (instead of going through id_make_local) maybe...
- *
- * We'll probably need at some point a true dependency graph between datablocks, but for now this should work
- * good enough (performances is not a critical point here anyway).
+ * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances
+ * are now *reasonably* OK.
*/
-void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
+void BKE_library_make_local(
+ Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *id_next;
+ ID *id;
int a;
+ LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
LinkNode *linked_loop_candidates = NULL;
- MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__);
+ MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ /* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1657,54 +1661,80 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
* by real datablocks responsible of them. */
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
- for (; id; id = id_next) {
+ for (; id; id = id->next) {
id->newid = NULL;
id->tag &= ~LIB_TAG_DOIT;
- id_next = id->next; /* id is possibly being inserted again */
- /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
+ if (id->lib == NULL) {
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
- * (very nasty to discover all your links are lost after appending)
- * */
- if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
- ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
+ * (very nasty to discover all your links are lost after appending).
+ * Also, never ever make proxified objects local, would not make any sense. */
+ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ELEM(lib, NULL, id->lib) &&
+ !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
- if (lib == NULL || id->lib == lib) {
- if (id->lib) {
- /* In this specific case, we do want to make ID local even if it has no local usage yet... */
- if (GS(id->name) == ID_OB) {
- /* Special case for objects because we don't want proxy pointers to be
- * cleared yet. This will happen down the road in this function.
- */
- BKE_object_make_local_ex(bmain, (Object*)id, true, false);
- }
- else {
- id_make_local(bmain, id, false, true);
- }
-
- if (id->newid) {
- BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem);
- }
- }
- else {
- id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
- }
- }
+ BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
- if (set_fake) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* do not set fake user on objects, groups (instancing) */
- id_fake_user_set(id);
- }
- }
+ /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
+ * local data), others will need to be duplicated and further processed later. */
+ BKE_library_indirectly_used_data_tag_clear(bmain);
+
+ /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
+ * which involves more complex checks and might instead create a local copy of original linked ID. */
+ for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
+ it_next = it->next;
+ id = it->link;
+
+ if (id->tag & LIB_TAG_DOIT) {
+ /* We know all users of this object are local or will be made fully local, even if currently there are
+ * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
+ * that data block local. Saves a tremendous amount of time with complex scenes... */
+ id_clear_lib_data_ex(bmain, id, true);
+ BKE_id_expand_local(id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
+ if (id->newid) {
+ /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
+ BLI_linklist_prepend_nlink(&copied_ids, id, it);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
}
}
}
- /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
- * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
- * See T48907. */
+ /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
+ * remaining linked original counterpart may not be needed anymore... */
+ todo_ids = NULL;
+
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated loop,
+ * as lbarray ordering is not enough to ensure us we did catch all dependencies
+ * (e.g. if making local a parent object before its child...). See T48907. */
for (LinkNode *it = copied_ids; it; it = it->next) {
id = it->link;
@@ -1712,9 +1742,18 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
BLI_assert(id->lib != NULL);
BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (old_to_new_ids) {
+ BLI_ghash_insert(old_to_new_ids, id, id->newid);
+ }
+
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
}
- /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+ /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end...
* Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
bool do_loop = true;
while (do_loop) {
@@ -1761,11 +1800,6 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
}
}
- /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
- * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
- else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
- id_us_ensure_real(id->newid);
- }
if (!is_local) {
if (!is_lib) { /* Not used at all, we can free it! */
@@ -1773,7 +1807,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
it->link = NULL;
do_loop = true;
}
- else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ else if ((id->tag & LIB_TAG_DOIT) == 0) { /* Check TAG_DOIT to avoid adding same ID several times... */
/* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL
* later we can skip it in lib-dependency cycles search later. */
BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem);
@@ -1791,9 +1826,9 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
}
}
- /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks.
+ /* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks.
* Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
- BKE_library_tag_unused_linked_data(bmain, false);
+ BKE_library_unused_linked_data_set_tag(bmain, false);
for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
if (it->link == NULL) {
continue;
@@ -1806,16 +1841,23 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
/* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
* archipelagos, so no need to check again after we have deleted one, as done in previous step. */
if (id->tag & LIB_TAG_DOIT) {
+ /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
+ * Setting it to NULL may not be 100% correct, but should be safe and do the work. */
+ if (GS(id->name) == ID_OB) {
+ ((Object *)id)->data = NULL;
+ }
+
/* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
* directly wipe them out without caring about clearing their usages.
* However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
* So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
-#if 0
- BKE_libblock_free_ex(bmain, id, false);
+#if 1
+ BKE_libblock_free_ex(bmain, id, false, true);
#else
BKE_libblock_unlink(bmain, id, false, false);
BKE_libblock_free(bmain, id);
#endif
+ ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */
it->link = NULL;
}
}
@@ -1888,3 +1930,13 @@ void BKE_library_filepath_set(Library *lib, const char *filepath)
BLI_path_abs(lib->filepath, basepath);
}
}
+
+void BKE_id_tag_set_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_or_uint32((uint32_t *)&id->tag, tag);
+}
+
+void BKE_id_tag_clear_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_and_uint32((uint32_t *)&id->tag, ~tag);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index cec7fbacd80..fa75c906fb1 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -1170,8 +1170,9 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
*is_used_linked = (iter.count_indirect != 0);
}
-
-static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+/* ***** IDs usages.checking/tagging. ***** */
+static int foreach_libblock_used_linked_data_tag_clear_cb(
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
{
bool *is_changed = user_data;
@@ -1206,7 +1207,7 @@ static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID
* \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
* LIB_TAG_DOIT are checked.
*/
-void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
+void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ListBase *lb_array[MAX_LIBARRAY];
@@ -1232,7 +1233,38 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
while (i--) {
for (ID *id = lb_array[i]->first; id; id = id->next) {
- BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
+ if (id->tag & LIB_TAG_DOIT) {
+ /* Unused ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ }
+ }
+ }
+}
+
+/**
+ * Untag linked data blocks used by other untagged linked datablocks.
+ * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original):
+ * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still
+ * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local.
+ */
+void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
+ /* Local or non-indirectly-used ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index b468e6436c8..40441034171 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -666,46 +666,23 @@ void BKE_libblock_relink_ex(
}
}
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
-void BKE_libblock_free_data(Main *bmain, ID *id)
+void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
{
if (id->properties) {
IDP_FreeProperty(id->properties);
MEM_freeN(id->properties);
}
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
}
/**
* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
*
* \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ * (only applies to main database)
+ * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
+ * \a id.
*/
-void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
{
ID *id = idv;
short type = GS(id->name);
@@ -830,12 +807,14 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
+ if (do_ui_user) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
}
BLI_remlink(lb, id);
@@ -848,7 +827,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
void BKE_libblock_free(Main *bmain, void *idv)
{
- BKE_libblock_free_ex(bmain, idv, true);
+ BKE_libblock_free_ex(bmain, idv, true, true);
}
void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index fa113ef5eef..a3fe73e4b11 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -58,6 +58,7 @@
#include "BLI_strict_flags.h"
+#include "atomic_ops.h"
#include "mikktspace.h"
// #define DEBUG_TIME
@@ -236,7 +237,9 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
/* accumulate */
- madd_v3_v3fl(vnors[ml[i].v], pnor, fac);
+ for (int k = 3; k--; ) {
+ atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac);
+ }
prev_edge = cur_edge;
}
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index b5f63588423..b5e1ded35bb 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -408,8 +408,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
/**
* Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
*/
-void BKE_object_defgroup_remove_all(Object *ob)
+void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
@@ -418,10 +419,12 @@ void BKE_object_defgroup_remove_all(Object *ob)
while (dg) {
bDeformGroup *next_dg = dg->next;
- if (edit_mode)
- object_defgroup_remove_edit_mode(ob, dg);
- else
- object_defgroup_remove_object_mode(ob, dg);
+ if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
+ if (edit_mode)
+ object_defgroup_remove_edit_mode(ob, dg);
+ else
+ object_defgroup_remove_object_mode(ob, dg);
+ }
dg = next_dg;
}
@@ -446,6 +449,15 @@ void BKE_object_defgroup_remove_all(Object *ob)
}
/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
+void BKE_object_defgroup_remove_all(struct Object *ob)
+{
+ BKE_object_defgroup_remove_all_ex(ob, false);
+}
+
+
+/**
* Get MDeformVert vgroup data from given object. Should only be used in Object mode.
*
* \return True if the id type supports weights.
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index ff69f381b06..4fe4d6e75a6 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -977,7 +977,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- atomic_add_fl(&vnors[v][k], fn[k]);
+ atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
}
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 55f9f384081..a821578db1a 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
*
* Its assumed that \a l_radial_first is never forming the target face.
*/
-static bool bm_face_exists_tri_from_loop_vert(
- BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
{
BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
if (l_radial_first->radial_next != l_radial_first) {
@@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert(
do {
BLI_assert(l_radial_iter->f->len == 3);
if (l_radial_iter->prev->v == v_opposite) {
- *r_face_existing = l_radial_iter->f;
- return true;
+ return l_radial_iter->f;
}
} while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
}
- return false;
+ return NULL;
}
/**
@@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create(
PBVHNode *node = &bvh->nodes[node_index];
/* ensure we never add existing face */
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
@@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge(
* deletion as well. Prevents extraneous "flaps" from being
* created. */
#if 0
- if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+ if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
#else
- if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+ if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
{
- BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index c3ae5736aa9..ebf9f017731 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -65,13 +65,22 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
-#ifdef WITH_BULLET
-
/* ************************************** */
/* Memory Management */
/* Freeing Methods --------------------- */
+#ifndef WITH_BULLET
+
+static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {}
+static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {}
+static void RB_dworld_delete(void *UNUSED(world)) {}
+static void RB_body_delete(void *UNUSED(body)) {}
+static void RB_shape_delete(void *UNUSED(shape)) {}
+static void RB_constraint_delete(void *UNUSED(con)) {}
+
+#endif
+
/* Free rigidbody world */
void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
{
@@ -165,6 +174,8 @@ void BKE_rigidbody_free_constraint(Object *ob)
ob->rigidbody_constraint = NULL;
}
+#ifdef WITH_BULLET
+
/* Copying Methods --------------------- */
/* These just copy the data, clearing out references to physics objects.
@@ -804,6 +815,18 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+
RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
/* fall-through */
case RBC_TYPE_6DOF:
@@ -1072,9 +1095,15 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty
rbc->spring_damping_x = 0.5f;
rbc->spring_damping_y = 0.5f;
rbc->spring_damping_z = 0.5f;
+ rbc->spring_damping_ang_x = 0.5f;
+ rbc->spring_damping_ang_y = 0.5f;
+ rbc->spring_damping_ang_z = 0.5f;
rbc->spring_stiffness_x = 10.0f;
rbc->spring_stiffness_y = 10.0f;
rbc->spring_stiffness_z = 10.0f;
+ rbc->spring_stiffness_ang_x = 10.0f;
+ rbc->spring_stiffness_ang_y = 10.0f;
+ rbc->spring_stiffness_ang_z = 10.0f;
rbc->motor_lin_max_impulse = 1.0f;
rbc->motor_lin_target_velocity = 1.0f;
@@ -1602,9 +1631,6 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_free_object(Object *ob) {}
-void BKE_rigidbody_free_constraint(Object *ob) {}
struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 05540f51588..e8970d416e9 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
smd->domain->point_cache[0] = NULL;
+ if (smd->domain->coba) {
+ MEM_freeN(smd->domain->coba);
+ }
+
MEM_freeN(smd->domain);
smd->domain = NULL;
}
@@ -544,6 +548,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->slice_depth = 0.5f;
smd->domain->slice_axis = 0;
smd->domain->vector_scale = 1.0f;
+
+ smd->domain->coba = NULL;
+ smd->domain->coba_field = FLUID_FIELD_DENSITY;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -646,6 +653,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
tsmd->domain->draw_velocity = smd->domain->draw_velocity;
tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
tsmd->domain->vector_scale = smd->domain->vector_scale;
+
+ if (smd->domain->coba) {
+ tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+ }
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 3132a8e27e7..f20885b1e8f 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -251,7 +251,8 @@ void BKE_sound_init(struct Main *bmain)
void BKE_sound_init_main(struct Main *bmain)
{
#ifdef WITH_JACK
- AUD_setSynchronizerCallback(sound_sync_callback, bmain);
+ if (sound_device)
+ AUD_setSynchronizerCallback(sound_sync_callback, bmain);
#else
(void)bmain; /* unused */
#endif
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 436cd2b8fde..fc2d9674c2f 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -237,7 +237,7 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_assert(pool->num >= done);
pool->num -= done;
- atomic_sub_z(&pool->currently_running_tasks, done);
+ atomic_sub_and_fetch_z(&pool->currently_running_tasks, done);
pool->done += done;
if (pool->num == 0)
@@ -292,7 +292,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
continue;
}
- if (atomic_add_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
+ if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
pool->num_threads == 0)
{
*task = current_task;
@@ -301,7 +301,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
break;
}
else {
- atomic_sub_z(&pool->currently_running_tasks, 1);
+ atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1);
}
}
if (!found_task)
@@ -669,7 +669,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* if found task, do it, otherwise wait until other tasks are done */
if (found_task) {
/* run task */
- atomic_add_z(&pool->currently_running_tasks, 1);
+ atomic_add_and_fetch_z(&pool->currently_running_tasks, 1);
work_task->run(pool, work_task->taskdata, 0);
/* delete task */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 0de883fe7bf..5c460c7b176 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -5095,6 +5095,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
smd->domain->tex_wt = NULL;
+ smd->domain->coba = newdataadr(fd, smd->domain->coba);
smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
if (!smd->domain->effector_weights)
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 14e02c9ffb6..8133d0496fa 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -53,6 +53,7 @@
#include "DNA_actuator_types.h"
#include "DNA_view3d_types.h"
#include "DNA_smoke_types.h"
+#include "DNA_rigidbody_types.h"
#include "DNA_genfile.h"
@@ -1426,7 +1427,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- {
+ if (!MAIN_VERSION_ATLEAST(main, 278, 3)) {
for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
if (scene->toolsettings != NULL) {
ToolSettings *ts = scene->toolsettings;
@@ -1438,5 +1439,31 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc) {
+ rbc->spring_stiffness_ang_x = 10.0;
+ rbc->spring_stiffness_ang_y = 10.0;
+ rbc->spring_stiffness_ang_z = 10.0;
+ rbc->spring_damping_ang_x = 0.5;
+ rbc->spring_damping_ang_y = 0.5;
+ rbc->spring_damping_ang_z = 0.5;
+ }
+ }
+ }
+
+ /* constant detail for sculpting is now a resolution value instead of
+ * a percentage, we reuse old DNA struct member but convert it */
+ for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (scene->toolsettings != NULL) {
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) {
+ ts->sculpt->constant_detail = 100.0f / ts->sculpt->constant_detail;
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index b02b76118a2..f2fef5d476b 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1729,6 +1729,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
smd->domain->point_cache[1]->step = 1;
write_pointcaches(wd, &(smd->domain->ptcaches[1]));
+
+ if (smd->domain->coba) {
+ writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
+ }
}
writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 72ea7bd7f5d..104df625ee6 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -245,7 +245,7 @@ typedef struct BMesh {
/* ID of the shape key this bmesh came from */
int shapenr;
- int walkers, totflags;
+ int totflags;
ListBase selected;
BMFace *act_face;
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 4d92baab6eb..132a7ccd4fa 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -626,7 +626,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void
BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT);
}
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v)
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
{
BMHeader *ele_dst = ele_dst_v;
const BMHeader *ele_src = ele_src_v;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 06bc5465a19..9c6483de42b 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -58,7 +58,7 @@ void BM_elem_attrs_copy_ex(
BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
const char hflag_mask);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v);
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize);
BMesh *BM_mesh_copy(BMesh *bm_old);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e83b752947c..0cd91107171 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add(
#endif
BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag);
- bmesh_radial_append(starte, l);
+ bmesh_radial_loop_append(starte, l);
#ifdef USE_BMESH_HOLES
lst->first = lst->last = l;
@@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add(
#else
f->l_first = l;
#endif
-
- l->f = f;
return l;
}
@@ -446,26 +444,20 @@ BMFace *BM_face_create(
if (create_flag & BM_CREATE_NO_DOUBLE) {
/* Check if face already exists */
- const bool is_overlap = BM_face_exists(verts, len, &f);
- if (is_overlap) {
+ f = BM_face_exists(verts, len);
+ if (f != NULL) {
return f;
}
- else {
- BLI_assert(f == NULL);
- }
}
f = bm_face_create__internal(bm);
startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag);
-
- startl->v = verts[0];
- startl->e = edges[0];
+
for (i = 1; i < len; i++) {
l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag);
-
- l->f = f;
- bmesh_radial_append(edges[i], l);
+
+ bmesh_radial_loop_append(edges[i], l);
l->prev = lastl;
lastl->next = l;
@@ -904,7 +896,7 @@ void BM_face_kill(BMesh *bm, BMFace *f)
do {
l_next = l_iter->next;
- bmesh_radial_loop_remove(l_iter, l_iter->e);
+ bmesh_radial_loop_remove(l_iter->e, l_iter);
bm_kill_only_loop(bm, l_iter);
} while ((l_iter = l_next) != l_first);
@@ -949,7 +941,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
l_next = l_iter->next;
e = l_iter->e;
- bmesh_radial_loop_remove(l_iter, e);
+ bmesh_radial_loop_remove(e, l_iter);
bm_kill_only_loop(bm, l_iter);
if (e->l == NULL) {
@@ -981,23 +973,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
*/
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
-
- if (e->l) {
- BMLoop *l = e->l, *lnext, *startl = e->l;
-
- do {
- lnext = l->radial_next;
- if (lnext->f == l->f) {
- BM_face_kill(bm, l->f);
- break;
- }
-
- BM_face_kill(bm, l->f);
-
- if (l == lnext)
- break;
- l = lnext;
- } while (l != startl);
+ while (e->l) {
+ BM_face_kill(bm, e->l->f);
}
bmesh_disk_edge_remove(e, e->v1);
@@ -1011,15 +988,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
*/
void BM_vert_kill(BMesh *bm, BMVert *v)
{
- if (v->e) {
- BMEdge *e, *e_next;
-
- e = v->e;
- while (v->e) {
- e_next = bmesh_disk_edge_next(e, v);
- BM_edge_kill(bm, e);
- e = e_next;
- }
+ while (v->e) {
+ BM_edge_kill(bm, v->e);
}
bm_kill_only_vert(bm, v);
@@ -1046,78 +1016,73 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
* \brief Loop Reverse
*
* Changes the winding order of a face from CW to CCW or vice versa.
- * This euler is a bit peculiar in comparison to others as it is its
- * own inverse.
- *
- * BMESH_TODO: reinsert validation code.
*
* \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
* (use when flipping normals, disable when mirroring, eg: symmetrize).
- *
- * \return Success
*/
-static bool bm_loop_reverse_loop(
+void bmesh_loop_reverse(
BMesh *bm, BMFace *f,
-#ifdef USE_BMESH_HOLES
- BMLoopList *lst,
-#endif
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
+ BMLoop *l_first = f->l_first;
-#ifdef USE_BMESH_HOLES
- BMLoop *l_first = lst->first;
+ /* track previous cycles radial state */
+ BMEdge *e_prev = l_first->prev->e;
+ BMLoop *l_prev_radial_next = l_first->prev->radial_next;
+ BMLoop *l_prev_radial_prev = l_first->prev->radial_prev;
+ bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next;
+
+ BMLoop *l_iter = l_first;
+ do {
+ BMEdge *e_iter = l_iter->e;
+ BMLoop *l_iter_radial_next = l_iter->radial_next;
+ BMLoop *l_iter_radial_prev = l_iter->radial_prev;
+ bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
+
+#if 0
+ bmesh_radial_loop_remove(e_iter, l_iter);
+ bmesh_radial_loop_append(e_prev, l_iter);
#else
- BMLoop *l_first = f->l_first;
-#endif
+ /* inline loop reversal */
+ if (is_prev_boundary) {
+ /* boundary */
+ l_iter->radial_next = l_iter;
+ l_iter->radial_prev = l_iter;
+ }
+ else {
+ /* non-boundary, replace radial links */
+ l_iter->radial_next = l_prev_radial_next;
+ l_iter->radial_prev = l_prev_radial_prev;
+ l_prev_radial_next->radial_prev = l_iter;
+ l_prev_radial_prev->radial_next = l_iter;
+ }
- const int len = f->len;
- BMLoop *l_iter, *oldprev, *oldnext;
- BMEdge **edar = BLI_array_alloca(edar, len);
- int i, j, edok;
+ if (e_iter->l == l_iter) {
+ e_iter->l = l_iter->next;
+ }
+ l_iter->e = e_prev;
+#endif
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
- bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e));
- }
+ SWAP(BMLoop *, l_iter->next, l_iter->prev);
- /* actually reverse the loop */
- for (i = 0, l_iter = l_first; i < len; i++) {
- oldnext = l_iter->next;
- oldprev = l_iter->prev;
- l_iter->next = oldprev;
- l_iter->prev = oldnext;
- l_iter = oldnext;
-
if (cd_loop_mdisp_offset != -1) {
MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
}
- }
- if (len == 2) { /* two edged face */
- /* do some verification here! */
- l_first->e = edar[1];
- l_first->next->e = edar[0];
- }
- else {
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
- edok = 0;
- for (j = 0; j < len; j++) {
- edok = BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]);
- if (edok) {
- l_iter->e = edar[j];
- break;
- }
- }
- }
- }
- /* rebuild radial */
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next)
- bmesh_radial_append(l_iter->e, l_iter);
+ e_prev = e_iter;
+ l_prev_radial_next = l_iter_radial_next;
+ l_prev_radial_prev = l_iter_radial_prev;
+ is_prev_boundary = is_iter_boundary;
+
+ /* step to next (now swapped) */
+ } while ((l_iter = l_iter->prev) != l_first);
#ifndef NDEBUG
/* validate radial */
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+ int i;
+ for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) {
BM_CHECK_ELEMENT(l_iter);
BM_CHECK_ELEMENT(l_iter->e);
BM_CHECK_ELEMENT(l_iter->v);
@@ -1129,22 +1094,6 @@ static bool bm_loop_reverse_loop(
/* Loop indices are no more valid! */
bm->elem_index_dirty |= BM_LOOP;
-
- return true;
-}
-
-/**
- * \brief Flip the faces direction
- */
-bool bmesh_loop_reverse(
- BMesh *bm, BMFace *f,
- const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
-{
-#ifdef USE_BMESH_HOLES
- return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#else
- return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#endif
}
static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
@@ -1193,7 +1142,11 @@ static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_
return i;
}
-static bool disk_is_flagged(BMVert *v, const char api_flag)
+/**
+ * Return true when the vertex is manifold,
+ * attached to faces which are all flagged.
+ */
+static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
{
BMEdge *e = v->e;
@@ -1252,7 +1205,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE);
BMVert *v1 = NULL, *v2 = NULL;
- int i, tote = 0;
+ int i;
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
if (UNLIKELY(!totface)) {
@@ -1282,13 +1235,10 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
v1 = l_iter->v;
v2 = BM_edge_other_vert(l_iter->e, l_iter->v);
}
- tote++;
}
else if (rlen == 2) {
- int d1, d2;
-
- d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF);
- d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF);
+ const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF);
+ const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF);
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
@@ -1332,7 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
}
/* create region face */
- f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL;
+ f_new = BLI_array_count(edges) ?
+ BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL;
if (UNLIKELY(f_new == NULL)) {
/* Invalid boundary region to join faces */
goto error;
@@ -1350,10 +1301,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
} while (l2 != l_iter);
if (l2 != l_iter) {
- /* I think this is correct? */
+ /* loops share an edge, shared vert depends on winding */
if (l2->v != l_iter->v) {
l2 = l2->next;
}
+ BLI_assert(l_iter->v == l2->v);
BM_elem_attrs_copy(bm, bm, l2, l_iter);
}
@@ -1362,22 +1314,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
#ifdef USE_BMESH_HOLES
/* add holes */
BLI_movelisttolist(&f_new->loops, &holes);
-#endif
/* update loop face pointer */
-#ifdef USE_BMESH_HOLES
- for (lst = f_new->loops.first; lst; lst = lst->next)
-#endif
- {
-#ifdef USE_BMESH_HOLES
+ for (lst = f_new->loops.first; lst; lst = lst->next) {
l_iter = l_first = lst->first;
-#else
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
-#endif
do {
l_iter->f = f_new;
} while ((l_iter = l_iter->next) != l_first);
}
+#endif
bm_elements_systag_disable(faces, totface, _FLAG_JF);
BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF);
@@ -1585,8 +1530,8 @@ BMFace *bmesh_sfme(
} while ((l_iter = l_iter->next) != l_first);
/* link up the new loops into the new edges radial */
- bmesh_radial_append(e, l_f1);
- bmesh_radial_append(e, l_f2);
+ bmesh_radial_loop_append(e, l_f1);
+ bmesh_radial_loop_append(e, l_f2);
f2->len = f2len;
@@ -1693,18 +1638,18 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
#ifndef NDEBUG
int radlen = bmesh_radial_length(l_next);
#endif
- int first1 = 0, first2 = 0;
+ bool is_first = true;
/* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */
while (l_next) {
l = l_next;
l->f->len++;
l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL;
- bmesh_radial_loop_remove(l, NULL);
+ bmesh_radial_loop_unlink(l);
l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0);
l_new->prev = l;
- l_new->next = (l->next);
+ l_new->next = l->next;
l_new->prev->next = l_new;
l_new->next->prev = l_new;
l_new->v = v_new;
@@ -1715,36 +1660,26 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
l->e = e_new;
/* append l into e_new's rad cycle */
- if (!first1) {
- first1 = 1;
- l->radial_next = l->radial_prev = NULL;
- }
-
- if (!first2) {
- first2 = 1;
+ if (is_first) {
+ is_first = false;
l->radial_next = l->radial_prev = NULL;
}
- bmesh_radial_append(l_new->e, l_new);
- bmesh_radial_append(l->e, l);
+ bmesh_radial_loop_append(l_new->e, l_new);
+ bmesh_radial_loop_append(l->e, l);
}
else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) {
l_new->e = e_new;
l->e = e;
/* append l into e_new's rad cycle */
- if (!first1) {
- first1 = 1;
+ if (is_first) {
+ is_first = false;
l->radial_next = l->radial_prev = NULL;
}
- if (!first2) {
- first2 = 1;
- l->radial_next = l->radial_prev = NULL;
- }
-
- bmesh_radial_append(l_new->e, l_new);
- bmesh_radial_append(l->e, l);
+ bmesh_radial_loop_append(l_new->e, l_new);
+ bmesh_radial_loop_append(l->e, l);
}
}
@@ -1839,7 +1774,6 @@ BMEdge *bmesh_jekv(
BMEdge *e_old;
BMVert *v_old, *v_target;
BMLoop *l_kill;
- bool halt = false;
#ifndef NDEBUG
int radlen, i;
bool edok;
@@ -1860,9 +1794,9 @@ BMEdge *bmesh_jekv(
e_old = bmesh_disk_edge_next(e_kill, v_kill);
v_target = BM_edge_other_vert(e_kill, v_kill);
v_old = BM_edge_other_vert(e_old, v_kill);
- halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */
-
- if (halt) {
+
+ /* check for double edges */
+ if (BM_verts_in_edge(v_kill, v_target, e_old)) {
return NULL;
}
else {
@@ -2413,7 +2347,7 @@ void bmesh_vert_separate(
v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
if (copy_select) {
- BM_elem_select_copy(bm, bm, v_new, v);
+ BM_elem_select_copy(bm, v_new, v);
}
while ((e = BLI_SMALLSTACK_POP(edges))) {
@@ -2471,18 +2405,13 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
do {
BMEdge *e_orig = n_orig->link;
LinkNode *n_step = n_orig->next;
- LinkNode *n_prev = n_orig;
do {
BMEdge *e = n_step->link;
BLI_assert(e != e_orig);
if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
BM_edge_splice(bm, e_orig, e);
- n_prev->next = n_step->next;
- n_step = n_prev;
}
- } while ((void)
- (n_prev = n_step),
- (n_step = n_step->next));
+ } while ((n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
} while ((edges_separate = edges_separate->next));
@@ -2619,8 +2548,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
l = e_src->l;
BLI_assert(BM_vert_in_edge(e_dst, l->v));
BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
- bmesh_radial_loop_remove(l, e_src);
- bmesh_radial_append(e_dst, l);
+ bmesh_radial_loop_remove(e_src, l);
+ bmesh_radial_loop_append(e_dst, l);
}
BLI_assert(bmesh_radial_length(e_src->l) == 0);
@@ -2667,12 +2596,12 @@ void bmesh_edge_separate(
}
e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP);
- bmesh_radial_loop_remove(l_sep, e);
- bmesh_radial_append(e_new, l_sep);
+ bmesh_radial_loop_remove(e, l_sep);
+ bmesh_radial_loop_append(e_new, l_sep);
l_sep->e = e_new;
if (copy_select) {
- BM_elem_select_copy(bm, bm, e_new, e);
+ BM_elem_select_copy(bm, e_new, e);
}
BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
@@ -2855,8 +2784,8 @@ BMVert *bmesh_urmv_loop_multi(
do {
l_next = l_iter->radial_next;
if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
- bmesh_radial_loop_remove(l_iter, e);
- bmesh_radial_append(e_new, l_iter);
+ bmesh_radial_loop_remove(e, l_iter);
+ bmesh_radial_loop_append(e_new, l_iter);
l_iter->e = e_new;
}
} while ((l_iter = l_next) != l_first);
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index fb5702bc574..f72e9d7b198 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -75,7 +75,7 @@ void bmesh_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
const bool copy_select);
-bool bmesh_loop_reverse(
+void bmesh_loop_reverse(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 961b10d848a..96154f051f9 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
@@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index d3c847de64e..03165beb329 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
*/
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
- BMFace *f, *f2;
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
int len = 0;
@@ -132,16 +131,17 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
#if 0
/* handle specific case for three-valence. solve it by
* increasing valence to four. this may be hackish. . */
- BMLoop *loop = e->l;
- if (loop->v == v) loop = loop->next;
- if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false))
+ BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v);
+ BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l;
+
+ if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false))
return false;
if (!BM_disk_dissolve(bm, v)) {
return false;
}
#else
- if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) {
+ if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) {
return false;
}
else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) {
@@ -159,11 +159,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
}
/* handle two-valence */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) {
- return false;
+ if (e->l != e->l->radial_next) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
+ return false;
+ }
}
return true;
@@ -176,9 +175,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
done = true;
e = v->e;
do {
- f = NULL;
+ BMFace *f = NULL;
if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) {
- f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true);
+ f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true);
/* return if couldn't join faces in manifold
* conditions */
/* !disabled for testing why bad things happen */
@@ -204,12 +203,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
if (e->l) {
/* get remaining two faces */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2) {
+ if (e->l != e->l->radial_next) {
/* join two remaining faces */
- if (!BM_faces_join_pair(bm, f, f2, e, true)) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
return false;
}
}
@@ -224,30 +220,24 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
*
* Joins two adjacent faces together.
*
- * Because this method calls to #BM_faces_join to do its work, if a pair
- * of faces share multiple edges, the pair of faces will be joined at
- * every edge (not just edge \a e). This part of the functionality might need
- * to be reconsidered.
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
*
* If the windings do not match the winding of the new face will follow
- * \a f_a's winding (i.e. \a f_b will be reversed before the join).
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
*
- * \return pointer to the combined face
+ * \return The combined face or NULL on failure.
*/
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del)
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
- BMFace *faces[2] = {f_a, f_b};
-
- BMLoop *l_a = BM_face_edge_share_loop(f_a, e);
- BMLoop *l_b = BM_face_edge_share_loop(f_b, e);
-
- BLI_assert(l_a && l_b);
+ BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
if (l_a->v == l_b->v) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
- bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true);
+ bmesh_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
}
-
+
+ BMFace *faces[2] = {l_a->f, l_b->f};
return BM_faces_join(bm, faces, 2, do_del);
}
@@ -551,7 +541,7 @@ BMEdge *BM_vert_collapse_edge(
BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
if (tv2) {
/* only action, other calls here only get the edge to return */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del);
+ e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
}
}
@@ -598,18 +588,13 @@ BMVert *BM_edge_collapse(
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
BMVert *v_new, *v_other;
+ BMEdge *e_new;
BMFace **oldfaces = NULL;
- BMEdge *e_dummy;
BLI_array_staticdeclare(oldfaces, 32);
const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS);
BLI_assert(BM_vert_in_edge(e, v) == true);
- /* we need this for handling multi-res */
- if (!r_e) {
- r_e = &e_dummy;
- }
-
/* do we have a multi-res layer? */
if (cd_loop_mdisp_offset != -1) {
BMLoop *l;
@@ -630,17 +615,20 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
}
v_other = BM_edge_other_vert(e, v);
- v_new = bmesh_semv(bm, v, e, r_e);
+ v_new = bmesh_semv(bm, v, e, &e_new);
+ if (r_e != NULL) {
+ *r_e = e_new;
+ }
BLI_assert(v_new != NULL);
- BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new));
+ BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new));
BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other));
sub_v3_v3v3(v_new->co, v_other->co, v->co);
madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac);
- (*r_e)->head.hflag = e->head.hflag;
- BM_elem_attrs_copy(bm, bm, e, *r_e);
+ e_new->head.hflag = e->head.hflag;
+ BM_elem_attrs_copy(bm, bm, e, e_new);
/* v->v_new->v2 */
BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
@@ -656,7 +644,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
BM_face_calc_center_mean(oldfaces[i], f_center_old);
for (j = 0; j < 2; j++) {
- BMEdge *e1 = j ? *r_e : e;
+ BMEdge *e1 = j ? e_new : e;
BMLoop *l;
l = e1->l;
@@ -689,7 +677,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
/* fix boundaries a bit, doesn't work too well quite yet */
#if 0
for (j = 0; j < 2; j++) {
- BMEdge *e1 = j ? *r_e : e;
+ BMEdge *e1 = j ? e_new : e;
BMLoop *l, *l2;
l = e1->l;
@@ -991,6 +979,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
BMLoop *l1, *l2;
BMFace *f;
BMEdge *e_new = NULL;
+ char f_active_prev = 0;
char f_hflag_prev_1;
char f_hflag_prev_2;
@@ -1041,8 +1030,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
f_hflag_prev_1 = l1->f->head.hflag;
f_hflag_prev_2 = l2->f->head.hflag;
+ /* maintain active face */
+ if (bm->act_face == l1->f) {
+ f_active_prev = 1;
+ }
+ else if (bm->act_face == l2->f) {
+ f_active_prev = 2;
+ }
+
+ const bool is_flipped = !BM_edge_is_contiguous(e);
+
/* don't delete the edge, manually remove the edge after so we can copy its attributes */
- f = BM_faces_join_pair(bm, l1->f, l2->f, e, true);
+ f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true);
if (f == NULL) {
return NULL;
@@ -1062,6 +1061,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
if (BM_edge_face_pair(e_new, &fa, &fb)) {
fa->head.hflag = f_hflag_prev_1;
fb->head.hflag = f_hflag_prev_2;
+
+ if (f_active_prev == 1) {
+ bm->act_face = fa;
+ }
+ else if (f_active_prev == 2) {
+ bm->act_face = fb;
+ }
+
+ if (is_flipped) {
+ BM_face_normal_flip(bm, fb);
+
+ if (ccw) {
+ /* needed otherwise ccw toggles direction */
+ e_new->l = e_new->l->radial_next;
+ }
+ }
}
}
else {
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 2e557e3b606..5e95e9a2cc7 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v);
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index b5f9575aff5..7ca5640578a 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
*/
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
- BMIter liter;
- BMLoop *l_iter;
+ BMLoop *l_iter = BM_face_vert_share_loop(f, v);
BLI_assert(BM_edge_exists(v_prev, v) != NULL);
- BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
- if (l_iter->f == f) {
- break;
- }
- }
-
if (l_iter) {
if (l_iter->prev->v == v_prev) {
return l_iter->next;
@@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
* The faces loop direction is ignored.
* </pre>
*/
-
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
return l->next->next;
}
}
-
-
-
#endif
}
@@ -392,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle(
*/
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
- BMEdge *e;
-
- if (!v->e)
- return NULL;
-
- e = bmesh_disk_faceedge_find_first(v->e, v);
-
- if (!e)
- return NULL;
-
- return bmesh_radial_faceloop_find_first(e->l, v);
+ return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
/**
@@ -878,9 +857,18 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max)
*
* same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
*/
-bool BM_vert_face_check(BMVert *v)
+bool BM_vert_face_check(const BMVert *v)
{
- return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
+ if (v->e != NULL) {
+ const BMEdge *e_iter, *e_first;
+ e_first = e_iter = v->e;
+ do {
+ if (e_iter->l != NULL) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
}
/**
@@ -910,7 +898,7 @@ bool BM_vert_is_wire(const BMVert *v)
* A vertex is non-manifold if it meets the following conditions:
* 1: Loose - (has no edges/faces incident upon it).
* 2: Joins two distinct regions - (two pyramids joined at the tip).
- * 3: Is part of a an edge with more than 2 faces.
+ * 3: Is part of an edge with more than 2 faces.
* 4: Is part of a wire edge.
*/
bool BM_vert_is_manifold(const BMVert *v)
@@ -926,7 +914,8 @@ bool BM_vert_is_manifold(const BMVert *v)
/* count edges while looking for non-manifold edges */
e_first = e_iter = v->e;
- l_first = e_iter->l ? e_iter->l : NULL;
+ /* may be null */
+ l_first = e_iter->l;
do {
/* loose edge or edge shared by more than two faces,
* edges with 1 face user are OK, otherwise we could
@@ -1924,7 +1913,7 @@ BMEdge *BM_edge_find_double(BMEdge *e)
*
* \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
*/
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
+BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
BMEdge *e_iter, *e_first;
@@ -1963,10 +1952,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
}
if (i_walk == len) {
- if (r_existface) {
- *r_existface = l_iter_radial->f;
- }
- return true;
+ return l_iter_radial->f;
}
}
} while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
@@ -1975,10 +1961,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
}
- if (r_existface) {
- *r_existface = NULL;
- }
- return false;
+ return NULL;
}
@@ -2121,26 +2104,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
* \note The face may contain other verts \b not in \a varr.
*
* \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be assigned to \a r_f_overlap.
+ * in this case the first one found will be returned.
*
* \param varr Array of unordered verts.
* \param len \a varr array length.
- * \param r_f_overlap The overlapping face to return.
- * \return Success
+ * \return The face or NULL.
*/
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
BMFace *f;
int i;
- bool is_overlap = false;
+ BMFace *f_overlap = NULL;
LinkNode *f_lnk = NULL;
- if (r_f_overlap) {
- *r_f_overlap = NULL;
- }
-
#ifdef DEBUG
/* check flag isn't already set */
for (i = 0; i < len; i++) {
@@ -2154,10 +2132,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) {
if (len <= BM_verts_in_face_count(varr, len, f)) {
- if (r_f_overlap)
- *r_f_overlap = f;
-
- is_overlap = true;
+ f_overlap = f;
break;
}
@@ -2171,7 +2146,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP);
}
- return is_overlap;
+ return f_overlap;
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 10e4b9a15aa..a6a37767ee9 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
-bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -135,12 +135,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL
BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1);
+BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index cb302139a4c..8e484841568 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
* to store non-manifold conditions since BM does not keep track of region/shell information.
*
* Functions relating to this cycle:
- * - #bmesh_radial_append
+ * - #bmesh_radial_loop_append
* - #bmesh_radial_loop_remove
* - #bmesh_radial_facevert_count
* - #bmesh_radial_facevert_check
@@ -264,10 +264,12 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
{
BMEdge *e_iter;
- if (!BM_vert_in_edge(e, v))
+ if (!BM_vert_in_edge(e, v)) {
return false;
- if (bmesh_disk_count_ex(v, len + 1) != len || len == 0)
+ }
+ if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) {
return false;
+ }
e_iter = e;
do {
@@ -336,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
*/
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
- const BMEdge *e_find = e;
+ const BMEdge *e_iter = e;
do {
- if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
- return (BMEdge *)e_find;
+ if (e_iter->l != NULL) {
+ return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e);
}
- } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
+ return NULL;
+}
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
+{
+ const BMEdge *e_iter = e;
+ do {
+ if (e_iter->l != NULL) {
+ return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
return NULL;
}
@@ -389,6 +406,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l)
return true;
}
+void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
+{
+ if (e->l == NULL) {
+ e->l = l;
+ l->radial_next = l->radial_prev = l;
+ }
+ else {
+ l->radial_prev = e->l;
+ l->radial_next = e->l->radial_next;
+
+ e->l->radial_next->radial_prev = l;
+ e->l->radial_next = l;
+
+ e->l = l;
+ }
+
+ if (UNLIKELY(l->e && l->e != e)) {
+ /* l is already in a radial cycle for a different edge */
+ BMESH_ASSERT(0);
+ }
+
+ l->e = e;
+}
+
/**
* \brief BMESH RADIAL REMOVE LOOP
*
@@ -397,28 +438,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l)
* updated (in the case that the edge's link into the radial
* cycle was the loop which is being removed from the cycle).
*/
-void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e)
+void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
{
/* if e is non-NULL, l must be in the radial cycle of e */
- if (UNLIKELY(e && e != l->e)) {
+ if (UNLIKELY(e != l->e)) {
BMESH_ASSERT(0);
}
if (l->radial_next != l) {
- if (e && l == e->l)
+ if (l == e->l) {
e->l = l->radial_next;
+ }
l->radial_next->radial_prev = l->radial_prev;
l->radial_prev->radial_next = l->radial_next;
}
else {
- if (e) {
- if (l == e->l) {
- e->l = NULL;
- }
- else {
- BMESH_ASSERT(0);
- }
+ if (l == e->l) {
+ e->l = NULL;
+ }
+ else {
+ BMESH_ASSERT(0);
}
}
@@ -428,6 +468,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e)
l->e = NULL;
}
+/**
+ * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
+ * leaving the edge untouched.
+ */
+void bmesh_radial_loop_unlink(BMLoop *l)
+{
+ if (l->radial_next != l) {
+ l->radial_next->radial_prev = l->radial_prev;
+ l->radial_prev->radial_next = l->radial_next;
+ }
+
+ /* l is no longer in a radial cycle; empty the links
+ * to the cycle and the link back to an edge */
+ l->radial_next = l->radial_prev = NULL;
+ l->e = NULL;
+}
/**
* \brief BME RADIAL FIND FIRST FACE VERT
@@ -484,30 +540,6 @@ int bmesh_radial_length(const BMLoop *l)
return i;
}
-void bmesh_radial_append(BMEdge *e, BMLoop *l)
-{
- if (e->l == NULL) {
- e->l = l;
- l->radial_next = l->radial_prev = l;
- }
- else {
- l->radial_prev = e->l;
- l->radial_next = e->l->radial_next;
-
- e->l->radial_next->radial_prev = l;
- e->l->radial_next = l;
-
- e->l = l;
- }
-
- if (UNLIKELY(l->e && l->e != e)) {
- /* l is already in a radial cycle for a different edge */
- BMESH_ASSERT(0);
- }
-
- l->e = e;
-}
-
/**
* \brief RADIAL COUNT FACE VERT
*
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 07f94796bb2..0efb25da37c 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -52,11 +52,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* RADIAL CYCLE MANAGMENT */
-void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
-void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
+void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
/* note:
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 6ef0fd6b084..61179d7be70 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -398,7 +398,8 @@ static void bridge_loop_pair(
if (v_b != v_b_next) {
BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
- if (BM_face_exists(v_arr, 4, &f) == false) {
+ f = BM_face_exists(v_arr, 4);
+ if (f == NULL) {
/* copy if loop data if its is missing on one ring */
f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true);
@@ -411,7 +412,8 @@ static void bridge_loop_pair(
}
else {
BMVert *v_arr[3] = {v_a, v_b, v_a_next};
- if (BM_face_exists(v_arr, 3, &f) == false) {
+ f = BM_face_exists(v_arr, 3);
+ if (f == NULL) {
/* fan-fill a triangle */
f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 05efb14a699..6e3a8a1473d 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -322,12 +322,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
}
BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
if (f_new) {
/* maintain active face */
@@ -437,12 +437,12 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) {
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
/* maintain active face */
if (act_face && bm->act_face == NULL) {
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index c68130bc11d..f33a60ccc5c 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -136,7 +136,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
i++;
} while ((v != f_verts[0]));
- if (BM_face_exists(f_verts, i, NULL) == false) {
+ if (!BM_face_exists(f_verts, i)) {
BMFace *f;
/* don't use calc_edges option because we already have the edges */
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 9c41e4f2115..81ec2860cf7 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -119,7 +119,8 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
};
BMFace *f, *example = NULL;
- if (BM_face_exists(t->v, 3, &f)) {
+ f = BM_face_exists(t->v, 3);
+ if (f != NULL) {
/* If the operator is run with "use_existing_faces"
* disabled, but an output face in the hull is the
* same as a face in the existing mesh, it should not
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index bc620e4a020..655fb346976 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -361,16 +361,16 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float);
for (i = 0; i < totedge; i++) {
- BMFace *f_a, *f_b;
+ BMLoop *l_a, *l_b;
e = jedges[i].data;
- f_a = e->l->f;
- f_b = e->l->radial_next->f;
+ l_a = e->l;
+ l_b = e->l->radial_next;
/* check if another edge already claimed this face */
- if ((f_a->len == 3) && (f_b->len == 3)) {
+ if ((l_a->f->len == 3) && (l_b->f->len == 3)) {
BMFace *f_new;
- f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, true);
if (f_new) {
BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 6da591b23a0..0ad8247e539 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -160,7 +160,7 @@ finally:
}
if (STACK_SIZE(edges) >= 3) {
- if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) {
+ if (!BM_face_exists(verts, STACK_SIZE(edges))) {
BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP);
BLI_assert(f_new != f);
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 8938d086c1a..6bd3174d27a 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -253,10 +253,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
if (BMO_edge_flag_test(bm, e, ELE_NEW)) {
/* in rare cases the edges face will have already been removed from the edge */
if (LIKELY(e->l)) {
- BMFace *f_new = BM_faces_join_pair(
- bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMO_face_flag_enable(bm, f_new, ELE_NEW);
BM_edge_kill(bm, e);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 978cceee37c..e2c36299ddf 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -322,9 +322,7 @@ void BM_mesh_decimate_dissolve_ex(
i = BM_elem_index_get(e);
if (BM_edge_is_manifold(e)) {
- f_new = BM_faces_join_pair(bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMLoop *l_first, *l_iter;
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 0fc571bc0a8..92300ae66a2 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -74,7 +74,7 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) ||
((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)))
{
- if (!BM_face_exists(varr, tot_edge, NULL)) {
+ if (!BM_face_exists(varr, tot_edge)) {
return true;
}
}
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 6ff6de33d56..8f3bf88af65 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -317,11 +317,6 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
}
- if (mesh->getPositions().empty()) {
- fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
- return false;
- }
-
return true;
}
@@ -329,11 +324,15 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
{
// vertices
COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+ if (pos.empty()) {
+ return;
+ }
+
int stride = pos.getStride(0);
if (stride == 0) stride = 3;
-
- me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride;
- me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+
+ me->totvert = pos.getFloatValues()->getCount() / stride;
+ me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
MVert *mvert;
int i;
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index b16e2e2b0d3..908111ebae6 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -113,11 +113,6 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
node.addMatrix("transform",d_obmat);
break;
}
- case BC_TRANSFORMATION_TYPE_BOTH:
- {
- node.addMatrix("transform",d_obmat);
- /* fall-through */
- }
case BC_TRANSFORMATION_TYPE_TRANSROTLOC:
{
float loc[3], rot[3], scale[3];
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 0017c66836a..a4416608584 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -43,8 +43,7 @@ typedef enum BC_export_mesh_type {
typedef enum BC_export_transformation_type {
BC_TRANSFORMATION_TYPE_MATRIX,
- BC_TRANSFORMATION_TYPE_TRANSROTLOC,
- BC_TRANSFORMATION_TYPE_BOTH
+ BC_TRANSFORMATION_TYPE_TRANSROTLOC
} BC_export_transformation_type;
struct bContext;
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index e5c2b8ace4e..9a47c6b2438 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -383,7 +383,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
- atomic_add_u(&this->m_chunksFinished, 1);
+ atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
if (memoryBuffers) {
for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index bba5c8702b8..6bfd8ae3888 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -118,7 +118,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
* interpolaiton and (b) in such configuration multitex() sinply floor's the value
* which often produces artifacts.
*/
- if ((m_texture->imaflag & TEX_INTERPOL) == 0) {
+ if (m_texture != NULL && (m_texture->imaflag & TEX_INTERPOL) == 0) {
u += 0.5f / cx;
v += 0.5f / cy;
}
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index fd2a521bec5..ab12a8d5b3e 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -45,6 +45,7 @@ set(SRC
intern/builder/deg_builder_nodes.cc
intern/builder/deg_builder_pchanmap.cc
intern/builder/deg_builder_relations.cc
+ intern/builder/deg_builder_relations_keys.cc
intern/builder/deg_builder_transitive.cc
intern/debug/deg_debug_graphviz.cc
intern/eval/deg_eval.cc
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 0945da439ef..fdc86540171 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -51,8 +51,12 @@ extern "C" {
/* Graph Building -------------------------------- */
-/* Build depsgraph for the given scene, and dump results in given graph container */
-void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
+/* Build depsgraph for the given scene, and dump results in given
+ * graph container.
+ */
+void DEG_graph_build_from_scene(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene);
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
@@ -85,31 +89,69 @@ struct CacheFile;
struct Object;
typedef enum eDepsSceneComponentType {
- DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_SCENE_COMP_PARAMETERS,
+ /* Animation Component
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_SCENE_COMP_ANIMATION,
+ /* Sequencer Component (Scene Only). */
+ DEG_SCENE_COMP_SEQUENCER,
} eDepsSceneComponentType;
typedef enum eDepsObjectComponentType {
- DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
- DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
-
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_OB_COMP_PARAMETERS,
+ /* Generic "Proxy-Inherit" Component.
+ * TODO(sergey): Also for instancing of subgraphs?
+ */
+ DEG_OB_COMP_PROXY,
+ /* Animation Component.
+ *
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_OB_COMP_ANIMATION,
+ /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_TRANSFORM,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEG_OB_COMP_GEOMETRY,
+
/* Evaluation-Related Outer Types (with Subdata) */
- DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
- DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
-
- DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
- DEG_OB_COMP_SHADING, /* Material Shading Component */
- DEG_OB_COMP_CACHE, /* Cache Component */
+
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_EVAL_POSE,
+ /* Bone Component - Child/Subcomponent of Pose */
+ DEG_OB_COMP_BONE,
+
+ /* Particle Systems Component */
+ DEG_OB_COMP_EVAL_PARTICLES,
+ /* Material Shading Component */
+ DEG_OB_COMP_SHADING,
+ /* Cache Component */
+ DEG_OB_COMP_CACHE,
} eDepsObjectComponentType;
-void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
-void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
-void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
-void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description);
+void DEG_add_scene_relation(struct DepsNodeHandle *node,
+ struct Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle,
+ struct Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsObjectComponentType component,
+ const char *description);
/* TODO(sergey): Remove once all geometry update is granular. */
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
@@ -117,8 +159,22 @@ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short fla
/* Utility functions for physics modifiers */
typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
-void DEG_add_collision_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name);
-void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
+void DEG_add_collision_relations(struct DepsNodeHandle *handle,
+ struct Scene *scene,
+ Object *ob,
+ struct Group *group,
+ int layer,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction fn,
+ bool dupli,
+ const char *name);
+void DEG_add_forcefield_relations(struct DepsNodeHandle *handle,
+ struct Scene *scene,
+ Object *ob,
+ struct EffectorWeights *eff,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name);
/* ************************************************ */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 6169100d574..8939e4cc93a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -34,6 +34,8 @@
#include <stack>
#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -56,10 +58,46 @@ string deg_fcurve_id_name(const FCurve *fcu)
return string(fcu->rna_path) + index_buf;
}
+static bool check_object_needs_evaluation(Object *object)
+{
+ if (object->recalc & OB_RECALC_ALL) {
+ /* Object is tagged for update anyway, no need to re-tag it. */
+ return false;
+ }
+ if (object->type == OB_MESH) {
+ return object->derivedFinal == NULL;
+ }
+ else if (ELEM(object->type,
+ OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE))
+ {
+ return object->curve_cache == NULL;
+ }
+ return false;
+}
+
void deg_graph_build_finalize(Depsgraph *graph)
{
+ /* STEP 1: Make sure new invisible dependencies are ready for use.
+ *
+ * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
+ * to do it ahead of a time and don't spend time on flushing updates on
+ * every frame change.
+ */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ if (id_node->layers == 0 || 1) {
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (check_object_needs_evaluation(object)) {
+ id_node->tag_update(graph);
+ }
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ /* STEP 2: Flush visibility layers from children to parent. */
std::stack<OperationDepsNode *> stack;
-
foreach (OperationDepsNode *node, graph->operations) {
IDDepsNode *id_node = node->owner->owner;
node->done = 0;
@@ -78,7 +116,6 @@ void deg_graph_build_finalize(Depsgraph *graph)
node->owner->layers = id_node->layers;
id_node->id->tag |= LIB_TAG_DOIT;
}
-
while (!stack.empty()) {
OperationDepsNode *node = stack.top();
stack.pop();
@@ -104,8 +141,9 @@ void deg_graph_build_finalize(Depsgraph *graph)
}
}
}
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ /* STEP 3: Re-tag IDs for update if it was tagged before the relations
+ * update tag.
+ */
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
{
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
@@ -121,6 +159,13 @@ void deg_graph_build_finalize(Depsgraph *graph)
id_node->tag_update(graph);
id->tag &= ~LIB_TAG_DOIT;
}
+ else if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->recalc & OB_RECALC_ALL) {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
id_node->finalize_build();
}
GHASH_FOREACH_END();
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 225cc64ae4d..9b37aaa12ff 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -56,12 +56,14 @@ struct StackEntry {
void deg_graph_detect_cycles(Depsgraph *graph)
{
- /* Not is not visited at all during traversal. */
- const int NODE_NOT_VISITED = 0;
- /* Node has been visited during traversal and not in current stack. */
- const int NODE_VISITED = 1;
- /* Node has been visited during traversal and is in current stack. */
- const int NODE_IN_STACK = 2;
+ enum {
+ /* Not is not visited at all during traversal. */
+ NODE_NOT_VISITED = 0,
+ /* Node has been visited during traversal and not in current stack. */
+ NODE_VISITED = 1,
+ /* Node has been visited during traversal and is in current stack. */
+ NODE_IN_STACK = 2,
+ };
std::stack<StackEntry> traversal_stack;
foreach (OperationDepsNode *node, graph->operations) {
@@ -77,21 +79,23 @@ void deg_graph_detect_cycles(Depsgraph *graph)
entry.from = NULL;
entry.via_relation = NULL;
traversal_stack.push(entry);
- node->done = NODE_IN_STACK;
+ node->tag = NODE_IN_STACK;
}
else {
- node->done = NODE_NOT_VISITED;
+ node->tag = NODE_NOT_VISITED;
}
+ node->done = 0;
}
while (!traversal_stack.empty()) {
- StackEntry &entry = traversal_stack.top();
+ StackEntry& entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
- foreach (DepsRelation *rel, node->outlinks) {
+ for (int i = node->done; i < node->outlinks.size(); ++i) {
+ DepsRelation *rel = node->outlinks[i];
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if (to->done == NODE_IN_STACK) {
+ if (to->tag == NODE_IN_STACK) {
printf("Dependency cycle detected:\n");
printf(" '%s' depends on '%s' through '%s'\n",
to->full_identifier().c_str(),
@@ -107,23 +111,24 @@ void deg_graph_detect_cycles(Depsgraph *graph)
current->via_relation->name);
current = current->from;
}
- /* TODO(sergey): So called roussian rlette cycle solver. */
+ /* TODO(sergey): So called russian roulette cycle solver. */
rel->flag |= DEPSREL_FLAG_CYCLIC;
}
- else if (to->done == NODE_NOT_VISITED) {
+ else if (to->tag == NODE_NOT_VISITED) {
StackEntry new_entry;
new_entry.node = to;
new_entry.from = &entry;
new_entry.via_relation = rel;
traversal_stack.push(new_entry);
- to->done = NODE_IN_STACK;
+ to->tag = NODE_IN_STACK;
all_child_traversed = false;
+ node->done = i;
break;
}
}
}
if (all_child_traversed) {
- node->done = NODE_VISITED;
+ node->tag = NODE_VISITED;
traversal_stack.pop();
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 1812384440f..12050e3e003 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -34,7 +34,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include "MEM_guardedalloc.h"
@@ -109,6 +108,40 @@ extern "C" {
namespace DEG {
+namespace {
+
+struct BuilderWalkUserData {
+ DepsgraphNodeBuilder *builder;
+ Scene *scene;
+};
+
+static void modifier_walk(void *user_data,
+ struct Object * /*ob*/,
+ struct Object **obpoin,
+ int /*cd_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*obpoin) {
+ data->builder->build_object(data->scene, NULL, *obpoin);
+ }
+}
+
+void constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*idpoin) {
+ ID *id = *idpoin;
+ if (GS(id->name) == ID_OB) {
+ data->builder->build_object(data->scene, NULL, (Object *)id);
+ }
+ }
+}
+
+} /* namespace */
+
/* ************ */
/* Node Builder */
@@ -131,8 +164,7 @@ RootDepsNode *DepsgraphNodeBuilder::add_root_node()
IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
- const char *idtype_name = BKE_idcode_to_name(GS(id->name));
- return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]");
+ return m_graph->add_id_node(id, id->name);
}
TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
@@ -179,7 +211,7 @@ TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name)
+ const char *comp_name)
{
IDDepsNode *id_node = add_id_node(id);
ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name);
@@ -192,15 +224,19 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
- OperationDepsNode *op_node = comp_node->has_operation(opcode, description);
+ OperationDepsNode *op_node = comp_node->has_operation(opcode,
+ name,
+ name_tag);
if (op_node == NULL) {
- op_node = comp_node->add_operation(optype, op, opcode, description);
+ op_node = comp_node->add_operation(optype, op, opcode, name, name_tag);
m_graph->operations.push_back(op_node);
}
else {
- fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ fprintf(stderr,
+ "add_operation: Operation already exists - %s has %s at %p\n",
comp_node->identifier().c_str(),
op_node->identifier().c_str(),
op_node);
@@ -212,14 +248,15 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
- return add_operation_node(comp_node, optype, op, opcode, description);
+ return add_operation_node(comp_node, optype, op, opcode, name, name_tag);
}
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
@@ -228,38 +265,54 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string& description)
+ const char *name,
+ int name_tag)
{
- return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+ return add_operation_node(id,
+ comp_type,
+ "",
+ optype,
+ op,
+ opcode,
+ name,
+ name_tag);
}
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
- return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL;
+ return find_operation_node(id,
+ comp_type,
+ comp_name,
+ opcode,
+ name,
+ name_tag) != NULL;
}
OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
- return comp_node->has_operation(opcode, description);
+ return comp_node->has_operation(opcode, name, name_tag);
}
OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Code opcode,
- const string& description)
+ const char *name,
+ int name_tag)
{
- return find_operation_node(id, comp_type, "", opcode, description);
+ return find_operation_node(id, comp_type, "", opcode, name, name_tag);
}
/* **** Build functions for entity nodes **** */
@@ -386,19 +439,22 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
{
/*Object *ob = go->ob;*/
- /* Each "group object" is effectively a separate instance of the underlying
- * object data. When the group is evaluated, the transform results and/or
- * some other attributes end up getting overridden by the group
+ /* Each "group object" is effectively a separate instance of the
+ * underlying object data. When the group is evaluated, the transform
+ * results and/or some other attributes end up getting overridden by
+ * the group.
*/
}
- /* create a node for representing subgraph */
+ /* Create a node for representing subgraph. */
SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
subgraph_node->graph = subgraph;
- /* make a copy of the data this node will need? */
- // XXX: do we do this now, or later?
- // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed...
+ /* Make a copy of the data this node will need? */
+ /* XXX: do we do this now, or later? */
+ /* TODO: need API function which queries graph's ID's hash, and duplicates
+ * those blocks thoroughly with all outside links removed.
+ */
return subgraph_node;
}
@@ -407,18 +463,40 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
if (ob->id.tag & LIB_TAG_DOIT) {
IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
- id_node->layers |= base->lay;
+ if (base != NULL) {
+ id_node->layers |= base->lay;
+ }
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
IDDepsNode *id_node = add_id_node(&ob->id);
- id_node->layers |= base->lay;
+ if (base != NULL) {
+ id_node->layers |= base->lay;
+ }
ob->customdata_mask = 0;
- /* standard components */
+ /* Standard components. */
build_object_transform(scene, ob);
- /* object data */
+ if (ob->parent != NULL) {
+ build_object(scene, NULL, ob->parent);
+ }
+ if (ob->modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ }
+ if (ob->constraints.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
+ }
+
+ /* Object data. */
if (ob->data) {
/* type-specific data... */
switch (ob->type) {
@@ -428,15 +506,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
- {
- /* TODO(sergey): This way using this object's
- * properties as driver target works fine.
- *
- * Does this depend on other nodes?
- */
- add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
-
build_obdata_geom(scene, ob);
/* TODO(sergey): Only for until we support granular
* update of curves.
@@ -448,7 +517,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
}
}
break;
- }
case OB_ARMATURE: /* Pose */
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
@@ -617,12 +685,17 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
OperationDepsNode *driver_op = find_operation_node(id,
DEPSNODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- deg_fcurve_id_name(fcu));
+ fcu->rna_path,
+ fcu->array_index);
if (driver_op == NULL) {
- driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu),
- DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ driver_op = add_operation_node(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_animsys_eval_driver, _1, id, fcu),
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path,
+ fcu->array_index);
}
/* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */
@@ -807,7 +880,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
/* Rebuild pose if not up to date. */
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(ob, arm);
+ BKE_pose_rebuild_ex(ob, arm, false);
/* XXX: Without this animation gets lost in certain circumstances
* after loading file. Need to investigate further since it does
* not happen with simple scenes..
@@ -972,6 +1045,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
ID *obdata = (ID *)ob->data;
+ /* TODO(sergey): This way using this object's properties as driver target
+ * works fine.
+ *
+ * Does this depend on other nodes?
+ */
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_POST,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
* We'll get rid of this node as soon as all the granular update functions
@@ -979,35 +1064,45 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
*
* TODO(sergey): Get rid of this node.
*/
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob),
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST,
+ function_bind(BKE_object_eval_uber_data, _1, scene, ob),
DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, NULL,
- DEG_OPCODE_PLACEHOLDER, "Eval Init");
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
// TODO: "Done" operation
/* Modifiers */
if (ob->modifiers.first) {
- ModifierData *md;
-
- for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md),
- DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ for (ModifierData *md = (ModifierData *)ob->modifiers.first;
+ md != NULL;
+ md = md->next)
+ {
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_object_eval_modifier,
+ _1,
+ scene,
+ ob,
+ md),
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+ md->name);
}
}
/* materials */
if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma) {
+ if (ma != NULL) {
// XXX?!
ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
build_material(geom_node, ma);
@@ -1032,16 +1127,23 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
build_animdata(obdata);
- /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ /* Nodes for result of obdata's evaluation, and geometry
+ * evaluation on object.
+ */
switch (ob->type) {
case OB_MESH:
{
//Mesh *me = (Mesh *)ob->data;
/* evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_mesh_eval_geometry,
+ _1,
+ (Mesh *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
break;
}
@@ -1049,48 +1151,76 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
Object *mom = BKE_mball_basis_find(scene, ob);
- /* motherball - mom depends on children! */
+ /* Motherball - mom depends on children! */
if (mom == ob) {
/* metaball evaluation operations */
/* NOTE: only the motherball gets evaluated! */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_mball_eval_geometry,
+ _1,
+ (MetaBall *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
}
break;
}
case OB_CURVE:
+ case OB_SURF:
case OB_FONT:
{
- /* curve evaluation operations */
+ /* Curve/nurms evaluation operations. */
/* - calculate curve geometry (including path) */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
-
- /* - calculate curve path - this is used by constraints, etc. */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
- DEG_OPCODE_GEOMETRY_PATH, "Path");
- break;
- }
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_curve_eval_geometry,
+ _1,
+ (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+
+ /* Calculate curve path - this is used by constraints, etc. */
+ if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_curve_eval_path,
+ _1,
+ (Curve *)obdata),
+ DEG_OPCODE_GEOMETRY_PATH,
+ "Path");
+ }
- case OB_SURF: /* Nurbs Surface */
- {
- /* nurbs evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* Make sure objects used for bevel.taper are in the graph.
+ * NOTE: This objects might be not linked to the scene.
+ */
+ Curve *cu = (Curve *)obdata;
+ if (cu->bevobj != NULL) {
+ build_object(scene, NULL, cu->bevobj);
+ }
+ if (cu->taperobj != NULL) {
+ build_object(scene, NULL, cu->bevobj);
+ }
+ if (ob->type == OB_FONT && cu->textoncurve != NULL) {
+ build_object(scene, NULL, cu->textoncurve);
+ }
break;
}
- case OB_LATTICE: /* Lattice */
+ case OB_LATTICE:
{
- /* lattice evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* Lattice evaluation operations. */
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_lattice_eval_geometry,
+ _1,
+ (Lattice *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
break;
}
}
@@ -1171,15 +1301,20 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
/* nodetree's nodes... */
for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
- if (bnode->id) {
- if (GS(bnode->id->name) == ID_MA) {
- build_material(owner_node, (Material *)bnode->id);
+ ID *id = bnode->id;
+ if (id != NULL) {
+ short id_type = GS(id->name);
+ if (id_type == ID_MA) {
+ build_material(owner_node, (Material *)id);
}
- else if (bnode->type == ID_TE) {
- build_texture(owner_node, (Tex *)bnode->id);
+ else if (id_type == ID_TE) {
+ build_texture(owner_node, (Tex *)id);
+ }
+ else if (id_type == ID_IM) {
+ build_image((Image *)id);
}
else if (bnode->type == NODE_GROUP) {
- bNodeTree *group_ntree = (bNodeTree *)bnode->id;
+ bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
build_nodetree(owner_node, group_ntree);
}
@@ -1236,10 +1371,33 @@ void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
return;
}
tex_id->tag |= LIB_TAG_DOIT;
- /* texture itself */
+ /* Texture itself. */
build_animdata(tex_id);
- /* texture's nodetree */
+ /* Texture's nodetree. */
build_nodetree(owner_node, tex->nodetree);
+ /* Special cases for different IDs which texture uses. */
+ if (tex->type == TEX_IMAGE) {
+ if (tex->ima != NULL) {
+ build_image(tex->ima);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_image(Image *image) {
+ ID *image_id = &image->id;
+ if (image_id->tag & LIB_TAG_DOIT) {
+ return;
+ }
+ image_id->tag |= LIB_TAG_DOIT;
+ /* Image ID node itself. */
+ add_id_node(image_id);
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(image_id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Image Eval");
}
void DepsgraphNodeBuilder::build_compositor(Scene *scene)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index f378f076804..72dc73357bf 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -38,6 +38,7 @@ struct bGPdata;
struct ListBase;
struct GHash;
struct ID;
+struct Image;
struct FCurve;
struct Group;
struct Key;
@@ -75,43 +76,49 @@ struct DepsgraphNodeBuilder {
ComponentDepsNode *add_component_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name = "");
+ const char *comp_name = "");
OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name,
+ const char *comp_name,
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
bool has_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Code opcode,
- const string &description = "");
+ const char *name = "",
+ int name_tag = -1);
void build_scene(Main *bmain, Scene *scene);
SubgraphDepsNode *build_subgraph(Group *group);
@@ -142,6 +149,7 @@ struct DepsgraphNodeBuilder {
void build_material(DepsNode *owner_node, Material *ma);
void build_texture(DepsNode *owner_node, Tex *tex);
void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_image(Image *image);
void build_world(World *world);
void build_compositor(Scene *scene);
void build_gpencil(bGPdata *gpd);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 09c7d9ab9de..fe75de5e350 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -34,13 +34,12 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_blenlib.h"
-#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
@@ -211,10 +210,12 @@ OperationDepsNode *DepsgraphRelationBuilder::find_node(
return NULL;
}
- OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name);
+ OperationDepsNode *op_node = comp_node->find_operation(key.opcode,
+ key.name,
+ key.name_tag);
if (!op_node) {
fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
- DEG_OPNAMES[key.opcode], key.name.c_str());
+ DEG_OPNAMES[key.opcode], key.name);
}
return op_node;
}
@@ -236,7 +237,7 @@ OperationDepsNode *DepsgraphRelationBuilder::has_node(
if (!comp_node) {
return NULL;
}
- return comp_node->has_operation(key.opcode, key.name);
+ return comp_node->has_operation(key.opcode, key.name, key.name_tag);
}
void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
@@ -449,6 +450,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
if (ob->id.tag & LIB_TAG_DOIT) {
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
/* Object Transforms */
eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
@@ -500,7 +502,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
build_animdata(&ob->id);
// XXX: This should be hooked up by the build_animdata code
- if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ if (needs_animdata_node(&ob->id)) {
ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
}
@@ -837,11 +839,66 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
/* drivers */
for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
- OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ OperationKey driver_key(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path,
+ fcu->array_index);
/* create the driver's relations to targets */
build_driver(id, fcu);
+ /* Special case for array drivers: we can not multithread them because
+ * of the way how they work internally: animation system will write the
+ * whole array back to RNA even when changing individual array value.
+ *
+ * Some tricky things here:
+ * - array_index is -1 for single channel drivers, meaning we only have
+ * to do some magic when array_index is not -1.
+ * - We do relation from next array index to a previous one, so we don't
+ * have to deal with array index 0.
+ *
+ * TODO(sergey): Avoid liner lookup somehow.
+ */
+ if (fcu->array_index > 0) {
+ FCurve *fcu_prev = NULL;
+ for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first;
+ fcu_candidate != NULL;
+ fcu_candidate = fcu_candidate->next)
+ {
+ /* Writing to different RNA paths is */
+ if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) {
+ continue;
+ }
+ /* We only do relation from previous fcurve to previous one. */
+ if (fcu_candidate->array_index >= fcu->array_index) {
+ continue;
+ }
+ /* Choose fcurve with highest possible array index. */
+ if (fcu_prev == NULL ||
+ fcu_candidate->array_index > fcu_prev->array_index)
+ {
+ fcu_prev = fcu_candidate;
+ }
+ }
+ if (fcu_prev != NULL) {
+ OperationKey prev_driver_key(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu_prev->rna_path,
+ fcu_prev->array_index);
+ OperationKey driver_key(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path,
+ fcu->array_index);
+ add_relation(prev_driver_key,
+ driver_key,
+ DEPSREL_TYPE_OPERATION,
+ "[Driver Order]");
+ }
+ }
+
/* prevent driver from occurring before own animation... */
if (adt->action || adt->nla_tracks.first) {
add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,
@@ -853,7 +910,11 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
- OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ OperationKey driver_key(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path,
+ fcu->array_index);
bPoseChannel *pchan = NULL;
/* create dependency between driver and data affected by it */
@@ -1356,10 +1417,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
if (data->poletar != NULL) {
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
// XXX: same armature issues - ready vs done?
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
}
- else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
/* vertex group target */
/* NOTE: for now, we don't need to represent vertex groups separately... */
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
@@ -1527,7 +1588,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
"Armature Eval");
add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
- if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ if (needs_animdata_node(&ob->id)) {
ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
}
@@ -1765,7 +1826,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
* for either the modifier needing time, or that it is animated.
*/
/* XXX: Remove this hack when these links are added as part of build_animdata() instead */
- if (modifier_dependsOnTime(md) == false) {
+ if (modifier_dependsOnTime(md) == false && needs_animdata_node(&ob->id)) {
ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
add_relation(animation_key, mod_key, DEPSREL_TYPE_OPERATION, "Modifier Animation");
}
@@ -1848,15 +1909,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
// XXX: these needs geom data, but where is geom stored?
if (cu->bevobj) {
ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->bevobj);
add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
}
if (cu->taperobj) {
ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->taperobj);
add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
}
if (ob->type == OB_FONT) {
if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->textoncurve);
add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
}
}
@@ -2063,7 +2127,7 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt != NULL) {
- return adt->action != NULL;
+ return (adt->action != NULL) || (adt->nla_tracks.first != NULL);
}
return false;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 5240aa24b54..8d8ad6772b8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -81,108 +81,83 @@ struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct RootKey
-{
- RootKey() {}
+struct RootKey {
+ RootKey();
};
struct TimeSourceKey
{
- TimeSourceKey() : id(NULL) {}
- TimeSourceKey(ID *id) : id(id) {}
+ TimeSourceKey();
+ TimeSourceKey(ID *id);
- string identifier() const
- {
- return string("TimeSourceKey");
- }
+ string identifier() const;
ID *id;
};
struct ComponentKey
{
- ComponentKey() :
- id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
- {}
- ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
- id(id), type(type), name(name)
- {}
-
- string identifier() const
- {
- const char *idname = (id) ? id->name : "<None>";
+ ComponentKey();
+ ComponentKey(ID *id, eDepsNode_Type type, const char *name = "");
- char typebuf[5];
- BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
-
- return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
- }
+ string identifier() const;
ID *id;
eDepsNode_Type type;
- string name;
+ const char *name;
};
struct OperationKey
{
- OperationKey() :
- id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
- id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
- id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
- id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
- id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
- id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
- id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
- {}
-
- string identifier() const
- {
- char typebuf[5];
- BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
-
- return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
- }
-
+ OperationKey();
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *name,
+ int name_tag = -1);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ const char *name,
+ int name_tag);
+
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode);
+
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag = -1);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag = -1);
+
+ string identifier() const;
ID *id;
eDepsNode_Type component_type;
- string component_name;
+ const char *component_name;
eDepsOperation_Code opcode;
- string name;
+ const char *name;
+ int name_tag;
};
struct RNAPathKey
{
- // Note: see depsgraph_build.cpp for implementation
+ /* NOTE: see depsgraph_build.cpp for implementation */
RNAPathKey(ID *id, const char *path);
- RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
- id(id), ptr(ptr), prop(prop)
- {}
-
- string identifier() const
- {
- const char *id_name = (id) ? id->name : "<No ID>";
- const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
-
- return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')";
- }
+ RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop);
+ string identifier() const;
ID *id;
PointerRNA ptr;
@@ -270,7 +245,7 @@ protected:
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType& key,
- const string& default_name = "");
+ const char *default_name = "");
bool needs_animdata_node(ID *id);
@@ -280,7 +255,7 @@ private:
struct DepsNodeHandle
{
- DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
+ DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") :
builder(builder),
node(node),
default_name(default_name)
@@ -290,7 +265,7 @@ struct DepsNodeHandle
DepsgraphRelationBuilder *builder;
OperationDepsNode *node;
- const string &default_name;
+ const char *default_name;
};
/* Utilities for Builders ----------------------------------------------------- */
@@ -318,6 +293,7 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
else {
if (!op_from) {
/* XXX TODO handle as error or report if needed */
+ node_from = find_node(key_from);
fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
type, description, key_from.identifier().c_str());
}
@@ -383,7 +359,7 @@ void DepsgraphRelationBuilder::add_node_handle_relation(
template <typename KeyType>
DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
const KeyType &key,
- const string &default_name)
+ const char *default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
new file mode 100644
index 00000000000..7ada04e8f74
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+namespace DEG {
+
+/////////////////////////////////////////
+// Root.
+
+RootKey::RootKey()
+{
+}
+
+/////////////////////////////////////////
+// Time source.
+
+TimeSourceKey::TimeSourceKey()
+ : id(NULL)
+{
+}
+
+TimeSourceKey::TimeSourceKey(ID *id)
+ : id(id)
+{
+}
+
+string TimeSourceKey::identifier() const
+{
+ return string("TimeSourceKey");
+}
+
+/////////////////////////////////////////
+// Component.
+
+ComponentKey::ComponentKey()
+ : id(NULL),
+ type(DEPSNODE_TYPE_UNDEFINED),
+ name("")
+{
+}
+
+ComponentKey::ComponentKey(ID *id, eDepsNode_Type type, const char *name)
+ : id(id),
+ type(type),
+ name(name)
+{
+}
+
+string ComponentKey::identifier() const
+{
+ const char *idname = (id) ? id->name : "<None>";
+ char typebuf[5];
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
+ return string("ComponentKey(") +
+ idname + ", " + typebuf + ", '" + name + "')";
+}
+
+/////////////////////////////////////////
+// Operation.
+
+OperationKey::OperationKey()
+ : id(NULL),
+ component_type(DEPSNODE_TYPE_UNDEFINED),
+ component_name(""),
+ opcode(DEG_OPCODE_OPERATION),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(DEG_OPCODE_OPERATION),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(DEG_OPCODE_OPERATION),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+string OperationKey::identifier() const
+{
+ char typebuf[5];
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
+ return string("OperationKey(") +
+ "t: " + typebuf +
+ ", cn: '" + component_name +
+ "', c: " + DEG_OPNAMES[opcode] +
+ ", n: '" + name + "')";
+}
+
+/////////////////////////////////////////
+// RNA path.
+
+RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop)
+ : id(id),
+ ptr(ptr),
+ prop(prop)
+{
+}
+
+string RNAPathKey::identifier() const
+{
+ const char *id_name = (id) ? id->name : "<No ID>";
+ const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
+ return string("RnaPathKey(") + "id: " + id_name +
+ ", prop: " + prop_name + "')";
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
index 70cd5f11a47..0d56ce71c7d 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -321,7 +321,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
const DepsNode *node)
{
- string name = node->identifier().c_str();
+ string name = node->identifier();
if (node->type == DEPSNODE_TYPE_ID_REF) {
IDDepsNode *id_node = (IDDepsNode *)node;
char buf[256];
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 2b7c63767ab..3502267d9ca 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -32,8 +32,6 @@
#include "intern/depsgraph.h" /* own include */
-#include <string.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -53,6 +51,8 @@ extern "C" {
#include "RNA_access.h"
}
+#include <cstring>
+
#include "DEG_depsgraph.h"
#include "intern/nodes/deg_node.h"
@@ -116,7 +116,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
const PropertyRNA *prop,
ID **id,
eDepsNode_Type *type,
- string *subdata)
+ const char **subdata)
{
if (!ptr->type)
return false;
@@ -232,7 +232,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
{
ID *id;
eDepsNode_Type type;
- string name;
+ const char *name;
/* Get querying conditions. */
if (pointer_to_id_node_criteria(ptr, prop, &id)) {
@@ -240,8 +240,9 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
}
else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
IDDepsNode *id_node = find_id_node(id);
- if (id_node)
+ if (id_node != NULL) {
return id_node->find_component(type, name);
+ }
}
return NULL;
@@ -328,7 +329,7 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const
return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
-IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
+IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 08b264f8497..e668facd645 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -101,22 +101,6 @@ struct Depsgraph {
~Depsgraph();
/**
- * Find node which matches the specified description.
- *
- * \param id: ID block that is associated with this
- * \param subdata: identifier used for sub-ID data (e.g. bone)
- * \param type: type of node we're dealing with
- * \param name: custom identifier assigned to node
- *
- * \return A node matching the required characteristics if it exists
- * or NULL if no such node exists in the graph.
- */
- DepsNode *find_node(const ID *id,
- eDepsNode_Type type,
- const string &subdata,
- const string &name);
-
- /**
* Convenience wrapper to find node given just pointer + property.
*
* \param ptr: pointer to the data that node will represent
@@ -136,7 +120,7 @@ struct Depsgraph {
void clear_subgraph_nodes();
IDDepsNode *find_id_node(const ID *id) const;
- IDDepsNode *add_id_node(ID *id, const string &name = "");
+ IDDepsNode *add_id_node(ID *id, const char *name = "");
void remove_id_node(const ID *id);
void clear_id_nodes();
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 7a3b19e82c6..9952f714145 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -32,6 +32,8 @@
#include "MEM_guardedalloc.h"
+// #define DEBUG_TIME
+
extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
@@ -41,6 +43,11 @@ extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
+#endif
+
#include "BKE_main.h"
#include "BKE_collision.h"
#include "BKE_effect.h"
@@ -190,6 +197,10 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
*/
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
+#ifdef DEBUG_TIME
+ TIMEIT_START(DEG_graph_build_from_scene);
+#endif
+
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* 1) Generate all the nodes in the graph first */
@@ -239,6 +250,10 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
abort();
}
#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(DEG_graph_build_from_scene);
+#endif
}
/* Tag graph relations for update. */
@@ -309,7 +324,15 @@ void DEG_scene_graph_free(Scene *scene)
}
}
-void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name)
+void DEG_add_collision_relations(DepsNodeHandle *handle,
+ Scene *scene,
+ Object *ob,
+ Group *group,
+ int layer,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction fn,
+ bool dupli,
+ const char *name)
{
unsigned int numcollobj;
Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
@@ -327,7 +350,13 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *o
MEM_freeN(collobjs);
}
-void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
+void DEG_add_forcefield_relations(DepsNodeHandle *handle,
+ Scene *scene,
+ Object *ob,
+ EffectorWeights *effector_weights,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name)
{
ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false);
@@ -339,17 +368,33 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *
if (eff->psys) {
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient
+ * for up to date particles.
+ */
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
}
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain");
- DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain");
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_TRANSFORM,
+ "Smoke Force Domain");
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_GEOMETRY,
+ "Smoke Force Domain");
}
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- DEG_add_collision_relations(handle, scene, ob, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
+ DEG_add_collision_relations(handle,
+ scene,
+ ob,
+ NULL,
+ eff->ob->lay,
+ eModifierType_Collision,
+ NULL,
+ true,
+ "Force Absorption");
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index e5d3d1f5861..2d8e7dc841c 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -63,8 +63,8 @@ struct DepsNodeFactory {
virtual const char *tname() const = 0;
virtual DepsNode *create_node(const ID *id,
- const string &subdata,
- const string &name) const = 0;
+ const char *subdata,
+ const char *name) const = 0;
};
template <class NodeType>
@@ -73,7 +73,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
const char *tname() const { return NodeType::typeinfo.tname; }
- DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
+ DepsNode *create_node(const ID *id, const char *subdata, const char *name) const
{
DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
@@ -81,12 +81,14 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
node->type = type();
node->tclass = tclass();
- if (!name.empty())
+ if (name[0] != '\0') {
/* set name if provided ... */
node->name = name;
- else
+ }
+ else {
/* ... otherwise use default type name */
node->name = tname();
+ }
node->init(id, subdata);
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 4f27dab258d..e8ed03666a6 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -31,7 +31,7 @@
*/
#include <stdio.h>
-#include <cstring>
+#include <cstring> /* required for memset */
#include <queue>
extern "C" {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c3fd202d832..e926f83bcbe 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -152,7 +152,7 @@ static void deg_task_run_func(TaskPool *pool,
}
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
+ atomic_sub_and_fetch_uint32(&child->num_links_pending, 1);
}
if (child->num_links_pending == 0) {
bool is_scheduled = atomic_fetch_and_or_uint8(
@@ -287,7 +287,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
{
if (dec_parents) {
BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
+ atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
}
if (node->num_links_pending == 0) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
index 67d64aae8bf..060544a4407 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -30,10 +30,10 @@
* Implementation of tools for debugging the depsgraph
*/
-#include <cstring>
-
#include "intern/eval/deg_eval_debug.h"
+#include <cstring> /* required for STREQ later on. */
+
extern "C" {
#include "BLI_listbase.h"
#include "BLI_ghash.h"
@@ -53,10 +53,10 @@ namespace DEG {
DepsgraphStats *DepsgraphDebug::stats = NULL;
-static string get_component_name(eDepsNode_Type type, const string &name = "")
+static string get_component_name(eDepsNode_Type type, const char *name = "")
{
DepsNodeFactory *factory = deg_get_node_factory(type);
- if (name.empty()) {
+ if (name[0] != '\0') {
return string(factory->tname());
}
else {
@@ -116,7 +116,7 @@ void DepsgraphDebug::task_started(Depsgraph *graph,
*/
DepsgraphStatsComponent *comp_stats =
get_component_stats(id, get_component_name(comp->type,
- comp->name),
+ comp->name).c_str(),
true);
times_clear(comp_stats->times);
}
@@ -146,7 +146,7 @@ void DepsgraphDebug::task_completed(Depsgraph *graph,
DepsgraphStatsComponent *comp_stats =
get_component_stats(id,
get_component_name(comp->type,
- comp->name),
+ comp->name).c_str(),
true);
times_add(comp_stats->times, time);
}
@@ -226,7 +226,7 @@ DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
DepsgraphStatsID *id_stats,
- const string &name,
+ const char *name,
bool create)
{
DepsgraphStatsComponent *comp_stats;
@@ -234,13 +234,14 @@ DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
comp_stats != NULL;
comp_stats = comp_stats->next)
{
- if (STREQ(comp_stats->name, name.c_str()))
+ if (STREQ(comp_stats->name, name)) {
break;
+ }
}
if (!comp_stats && create) {
comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent),
"Depsgraph Component Stats");
- BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_strncpy(comp_stats->name, name, sizeof(comp_stats->name));
BLI_addtail(&id_stats->components, comp_stats);
}
return comp_stats;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
index 9109019eb2d..0bbe88cc9ca 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_debug.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
@@ -66,10 +66,10 @@ struct DepsgraphDebug {
static DepsgraphStatsID *get_id_stats(ID *id, bool create);
static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
- const string &name,
+ const char *name,
bool create);
static DepsgraphStatsComponent *get_component_stats(ID *id,
- const string &name,
+ const char *name,
bool create)
{
return get_component_stats(get_id_stats(id, create), name, create);
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index eb408f293de..57b25c10670 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -31,7 +31,7 @@
#include "intern/nodes/deg_node.h"
#include <stdio.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -72,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
DepsNode::DepsNode()
{
- name[0] = '\0';
+ name = "";
}
DepsNode::~DepsNode()
@@ -122,7 +122,7 @@ RootDepsNode::~RootDepsNode()
OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
}
-TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
+TimeSourceDepsNode *RootDepsNode::add_time_source(const char *name)
{
if (!time_source) {
DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
@@ -142,12 +142,24 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
+IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type,
+ const char *name)
+ : type(type), name(name)
+{
+}
+
+bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const
+{
+ return type == other.type &&
+ STREQ(name, other.name);
+}
+
static unsigned int id_deps_node_hash_key(const void *key_v)
{
const IDDepsNode::ComponentIDKey *key =
reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
return hash_combine(BLI_ghashutil_uinthash(key->type),
- BLI_ghashutil_strhash_p(key->name.c_str()));
+ BLI_ghashutil_strhash_p(key->name));
}
static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
@@ -173,7 +185,7 @@ static void id_deps_node_hash_value_free(void *value_v)
}
/* Initialize 'id' node - from pointer data given. */
-void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
+void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
{
/* Store ID-pointer. */
BLI_assert(id != NULL);
@@ -204,14 +216,14 @@ IDDepsNode::~IDDepsNode()
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
- const string &name) const
+ const char *name) const
{
ComponentIDKey key(type, name);
return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
- const string &name)
+ const char *name)
{
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
@@ -226,7 +238,7 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
return comp_node;
}
-void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
+void IDDepsNode::remove_component(eDepsNode_Type type, const char *name)
{
ComponentDepsNode *comp_node = find_component(type, name);
if (comp_node) {
@@ -281,7 +293,7 @@ static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
/* Subgraph Node ========================================== */
/* Initialize 'subgraph' node - from pointer data given. */
-void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata))
+void SubgraphDepsNode::init(const ID *id, const char *UNUSED(subdata))
{
/* Store ID-ref if provided. */
this->root_id = (ID *)id;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index b2262c4bd12..7c2f53840b6 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -32,6 +32,8 @@
#include "intern/depsgraph_types.h"
+#include "BLI_utildefines.h"
+
struct ID;
struct GHash;
struct Scene;
@@ -57,7 +59,7 @@ struct DepsNode {
};
/* Identifier - mainly for debugging purposes. */
- string name;
+ const char *name;
/* Structural type of node. */
eDepsNode_Type type;
@@ -78,8 +80,9 @@ struct DepsNode {
/* Nodes which depend on this one. */
Relations outlinks;
- /* Generic tag for traversal algorithms */
+ /* Generic tags for traversal algorithms. */
int done;
+ int tag;
/* Methods. */
@@ -90,7 +93,7 @@ struct DepsNode {
string full_identifier() const;
virtual void init(const ID * /*id*/,
- const string &/*subdata*/) {}
+ const char * /*subdata*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
@@ -129,7 +132,7 @@ struct RootDepsNode : public DepsNode {
RootDepsNode();
~RootDepsNode();
- TimeSourceDepsNode *add_time_source(const string &name = "");
+ TimeSourceDepsNode *add_time_source(const char *name = "");
/* scene that this corresponds to */
Scene *scene;
@@ -143,26 +146,21 @@ struct RootDepsNode : public DepsNode {
/* ID-Block Reference */
struct IDDepsNode : public DepsNode {
struct ComponentIDKey {
- ComponentIDKey(eDepsNode_Type type, const string &name = "")
- : type(type), name(name) {}
-
- bool operator== (const ComponentIDKey &other) const
- {
- return type == other.type && name == other.name;
- }
+ ComponentIDKey(eDepsNode_Type type, const char *name = "");
+ bool operator==(const ComponentIDKey &other) const;
eDepsNode_Type type;
- string name;
+ const char *name;
};
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
- const string &name = "") const;
+ const char *name = "") const;
ComponentDepsNode *add_component(eDepsNode_Type type,
- const string &name = "");
- void remove_component(eDepsNode_Type type, const string &name = "");
+ const char *name = "");
+ void remove_component(eDepsNode_Type type, const char *name = "");
void clear_components();
void tag_update(Depsgraph *graph);
@@ -189,7 +187,7 @@ struct IDDepsNode : public DepsNode {
/* Subgraph Reference. */
struct SubgraphDepsNode : public DepsNode {
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
~SubgraphDepsNode();
/* Instanced graph. */
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 01f33b6368b..06f91ac7fdc 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -31,7 +31,7 @@
#include "intern/nodes/deg_node_component.h"
#include <stdio.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
extern "C" {
#include "BLI_utildefines.h"
@@ -53,12 +53,50 @@ namespace DEG {
/* Standard Component Methods ============================= */
+ComponentDepsNode::OperationIDKey::OperationIDKey()
+ : opcode(DEG_OPCODE_OPERATION),
+ name(""),
+ name_tag(-1)
+{
+}
+
+ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode)
+ : opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+string ComponentDepsNode::OperationIDKey::identifier() const
+{
+ char codebuf[5];
+ BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
+ return string("OperationIDKey(") + codebuf + ", " + name + ")";
+}
+
+bool ComponentDepsNode::OperationIDKey::operator==(
+ const OperationIDKey &other) const
+{
+ return (opcode == other.opcode) &&
+ (STREQ(name, other.name)) &&
+ (name_tag == other.name_tag);
+}
+
static unsigned int comp_node_hash_key(const void *key_v)
{
const ComponentDepsNode::OperationIDKey *key =
reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
return hash_combine(BLI_ghashutil_uinthash(key->opcode),
- BLI_ghashutil_strhash_p(key->name.c_str()));
+ BLI_ghashutil_strhash_p(key->name));
}
static bool comp_node_hash_key_cmp(const void *a, const void *b)
@@ -95,7 +133,7 @@ ComponentDepsNode::ComponentDepsNode() :
/* Initialize 'component' node - from pointer data given */
void ComponentDepsNode::init(const ID * /*id*/,
- const string & /*subdata*/)
+ const char * /*subdata*/)
{
/* hook up eval context? */
// XXX: maybe this needs a special API?
@@ -114,7 +152,7 @@ ComponentDepsNode::~ComponentDepsNode()
string ComponentDepsNode::identifier() const
{
- string &idname = this->owner->name;
+ string idname = this->owner->name;
char typebuf[16];
sprintf(typebuf, "(%d)", type);
@@ -139,9 +177,11 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
}
}
-OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
+OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag) const
{
- OperationIDKey key(opcode, name);
+ OperationIDKey key(opcode, name, name_tag);
return find_operation(key);
}
@@ -151,21 +191,26 @@ OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
- const string &name) const
+ const char *name,
+ int name_tag) const
{
- OperationIDKey key(opcode, name);
+ OperationIDKey key(opcode, name, name_tag);
return has_operation(key);
}
-OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
+OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
{
- OperationDepsNode *op_node = has_operation(opcode, name);
+ OperationDepsNode *op_node = has_operation(opcode, name, name_tag);
if (!op_node) {
DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
- OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name);
+ OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
BLI_ghash_insert(operations_map, key, op_node);
/* set as entry/exit node of component (if appropriate) */
@@ -197,16 +242,6 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
return op_node;
}
-void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
-{
- /* unregister */
- OperationIDKey key(opcode, name);
- BLI_ghash_remove(operations_map,
- &key,
- comp_node_hash_key_free,
- comp_node_hash_key_free);
-}
-
void ComponentDepsNode::clear_operations()
{
if (operations_map != NULL) {
@@ -337,7 +372,7 @@ static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
/* Bone Component ========================================= */
/* Initialize 'bone component' node - from pointer data given */
-void BoneComponentDepsNode::init(const ID *id, const string &subdata)
+void BoneComponentDepsNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
ComponentDepsNode::init(id, subdata);
@@ -350,7 +385,7 @@ void BoneComponentDepsNode::init(const ID *id, const string &subdata)
/* bone-specific node data */
Object *ob = (Object *)id;
- this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
+ this->pchan = BKE_pose_channel_find_name(ob->pose, subdata);
}
DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 7dec8eaaa90..969771a29c9 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -53,50 +53,38 @@ struct ComponentDepsNode : public DepsNode {
struct OperationIDKey
{
eDepsOperation_Code opcode;
- string name;
-
-
- OperationIDKey() :
- opcode(DEG_OPCODE_OPERATION), name("")
- {}
- OperationIDKey(eDepsOperation_Code opcode) :
- opcode(opcode), name("")
- {}
- OperationIDKey(eDepsOperation_Code opcode, const string &name) :
- opcode(opcode), name(name)
- {}
-
- string identifier() const
- {
- char codebuf[5];
- BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
-
- return string("OperationIDKey(") + codebuf + ", " + name + ")";
- }
-
- bool operator==(const OperationIDKey &other) const
- {
- return (opcode == other.opcode) && (name == other.name);
- }
+ const char *name;
+ int name_tag;
+
+ OperationIDKey();
+ OperationIDKey(eDepsOperation_Code opcode);
+ OperationIDKey(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag);
+
+ string identifier() const;
+ bool operator==(const OperationIDKey &other) const;
};
/* Typedef for container of operations */
ComponentDepsNode();
~ComponentDepsNode();
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
OperationDepsNode *find_operation(eDepsOperation_Code opcode,
- const string &name) const;
+ const char *name,
+ int name_tag) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
OperationDepsNode *has_operation(eDepsOperation_Code opcode,
- const string &name) const;
+ const char *name,
+ int name_tag) const;
/**
* Create a new node for representing an operation and add this to graph
@@ -114,9 +102,9 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *add_operation(eDepsOperation_Type optype,
DepsEvalOperationCb op,
eDepsOperation_Code opcode,
- const string &name);
+ const char *name,
+ int name_tag);
- void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
void tag_update(Depsgraph *graph);
@@ -194,7 +182,7 @@ struct PoseComponentDepsNode : public ComponentDepsNode {
/* Bone Component */
struct BoneComponentDepsNode : public ComponentDepsNode {
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 5847af29ac2..9eed4dfe8d8 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -68,7 +68,7 @@ string OperationDepsNode::full_identifier() const
{
string owner_str = "";
if (owner->type == DEPSNODE_TYPE_BONE) {
- owner_str = owner->owner->name + "." + owner->name;
+ owner_str = string(owner->owner->name) + "." + owner->name;
}
else {
owner_str = owner->owner->name;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 262ce0b9e23..c0d6963acbb 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -57,6 +57,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_util.h"
#include "anim_intern.h"
@@ -263,7 +264,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index ece0f18e96e..47e73f9b777 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -1328,6 +1328,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
ED_armature_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 5015829f868..322476dcca0 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -626,7 +626,7 @@ void POSE_OT_flip_names(wmOperatorType *ot)
/* api callbacks */
ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode;
+ ot->poll = ED_operator_posemode_local;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index cd0ea23e2d3..8e8345d34c9 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -685,6 +685,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE: /* confirm */
case RETKEY:
+ case PADENTER:
{
/* return to normal cursor and header status */
ED_area_headerprint(pso->sa, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 7dcbe2cc24c..ae83e899649 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -84,7 +84,8 @@
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
@@ -95,6 +96,15 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
id_us_min(&gpd->id);
*gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+
+ /* if not exist brushes, create a new set */
+ if (ts) {
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ }
+ }
+
}
/* notifiers */
@@ -174,7 +184,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
/* if there's no existing Grease-Pencil data there, add some */
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -183,6 +194,14 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
if (*gpd_ptr == NULL)
*gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+ /* if not exist brushes, create a new set */
+ if (ts) {
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ }
+ }
+
/* add new layer now */
BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6a558d1c185..ec09add56b8 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -183,6 +183,7 @@ int ED_operator_uvmap(struct bContext *C);
int ED_operator_posemode_exclusive(struct bContext *C);
int ED_operator_posemode_context(struct bContext *C);
int ED_operator_posemode(struct bContext *C);
+int ED_operator_posemode_local(struct bContext *C);
int ED_operator_mask(struct bContext *C);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f5968397f65..a4afa958450 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -52,6 +52,8 @@ void ED_OT_flush_edits(struct wmOperatorType *ot);
/* undo.c */
void ED_undo_push(struct bContext *C, const char *str);
void ED_undo_push_op(struct bContext *C, struct wmOperator *op);
+void ED_undo_grouped_push(struct bContext *C, const char *str);
+void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop(struct bContext *C);
void ED_undo_redo(struct bContext *C);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 31598a44b09..d7f06b7db13 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -1083,6 +1083,15 @@ static int depthdropper_poll(bContext *C)
return 1;
}
}
+ else {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) {
+ return 1;
+ }
+ }
+ }
return 0;
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 863f5e3852c..f3eeadb6604 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2219,7 +2219,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
/* ******************* copy and paste ******************** */
/* c = copy, v = paste */
-static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
+static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array)
{
int buf_paste_len = 0;
const char *buf_paste = "";
@@ -2255,6 +2255,46 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
if (but->poin == NULL && but->rnapoin.data == NULL) {
/* pass */
}
+ else if (copy_array && but->rnapoin.data && but->rnaprop &&
+ ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION,
+ PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE,
+ PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS))
+ {
+ float values[4];
+ int array_length = RNA_property_array_length(&but->rnapoin, but->rnaprop);
+
+ if (mode == 'c') {
+ char buf_copy[UI_MAX_DRAW_STR];
+
+ if (array_length == 4) {
+ values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ }
+ else {
+ values[3] = 0.0f;
+ }
+ ui_but_v3_get(but, values);
+
+ BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", values[0], values[1], values[2], values[3]);
+ WM_clipboard_text_set(buf_copy, 0);
+ }
+ else {
+ if (sscanf(buf_paste, "[%f, %f, %f, %f]", &values[0], &values[1], &values[2], &values[3]) >= array_length) {
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+
+ ui_but_v3_set(but, values);
+ if (but->rnaprop && array_length == 4) {
+ RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, values[3]);
+ }
+ data->value = values[but->rnaindex];
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ else {
+ WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'");
+ show_report = true;
+ }
+ }
+ }
else if (mode == 'c') {
/* Get many decimal places, then strip trailing zeros.
* note: too high values start to give strange results */
@@ -6617,15 +6657,22 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
{
bScreen *sc = CTX_wm_screen(C);
+ const bool has_panel_category = UI_panel_category_is_visible(ar);
+ const bool any_item_visible = has_panel_category;
PointerRNA ptr;
uiPopupMenu *pup;
uiLayout *layout;
+ if (!any_item_visible) {
+ return;
+ }
+
RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr);
pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- if (UI_panel_category_is_visible(ar)) {
+
+ if (has_panel_category) {
char tmpstr[80];
BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse"));
uiItemR(layout, &ptr, "use_pin", 0, tmpstr, ICON_NONE);
@@ -6636,7 +6683,6 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
uiBut *but = block->buttons.last;
but->flag |= UI_BUT_HAS_SEP_CHAR;
}
-
}
UI_popup_menu_end(C, pup);
}
@@ -6959,7 +7005,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
/* handle copy-paste */
if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
- IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt)
+ IS_EVENT_MOD(event, ctrl, oskey) && !event->shift)
{
/* Specific handling for listrows, we try to find their overlapping tex button. */
if (but->type == UI_BTYPE_LISTROW) {
@@ -6969,7 +7015,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
data = but->active;
}
}
- ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
+ ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v', event->alt);
return WM_UI_HANDLER_BREAK;
}
/* handle drop */
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index ff9d2840e9c..65b12fcd64e 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -213,173 +213,6 @@ static void viconutil_set_point(GLint pt[2], int x, int y)
pt[1] = y;
}
-static void viconutil_draw_tri(GLint(*pts)[2])
-{
- glBegin(GL_TRIANGLES);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glVertex2iv(pts[2]);
- glEnd();
-}
-
-static void viconutil_draw_lineloop(GLint(*pts)[2], int numPoints)
-{
- int i;
-
- glBegin(GL_LINE_LOOP);
- for (i = 0; i < numPoints; i++) {
- glVertex2iv(pts[i]);
- }
- glEnd();
-}
-
-static void viconutil_draw_lineloop_smooth(GLint(*pts)[2], int numPoints)
-{
- glEnable(GL_LINE_SMOOTH);
- viconutil_draw_lineloop(pts, numPoints);
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void viconutil_draw_points(GLint(*pts)[2], int numPoints, int pointSize)
-{
- int i;
-
- glBegin(GL_QUADS);
- for (i = 0; i < numPoints; i++) {
- int x = pts[i][0], y = pts[i][1];
-
- glVertex2i(x - pointSize, y - pointSize);
- glVertex2i(x + pointSize, y - pointSize);
- glVertex2i(x + pointSize, y + pointSize);
- glVertex2i(x - pointSize, y + pointSize);
- }
- glEnd();
-}
-
-/* Drawing functions */
-
-static void vicon_x_draw(int x, int y, int w, int h, float alpha)
-{
- x += 3;
- y += 3;
- w -= 6;
- h -= 6;
-
- glEnable(GL_LINE_SMOOTH);
-
- glLineWidth(2.5);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, y);
- glVertex2i(x + w, y + h);
- glVertex2i(x + w, y);
- glVertex2i(x, y + h);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
-{
- int cx = x + w / 2;
- int cy = y + h / 2;
- int d = MAX2(2, h / 3);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy - d);
- glVertex2i(x + w, cy - d);
- glVertex2i(x, cy + d);
- glVertex2i(x + w, cy + d);
-
- glVertex2i(cx - d, y);
- glVertex2i(cx - d, y + h);
- glVertex2i(cx + d, y);
- glVertex2i(cx + d, y + h);
- glEnd();
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy);
- glVertex2i(x + w, cy);
- glVertex2i(cx, y);
- glVertex2i(cx, y + h);
- glEnd();
-}
-
-static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[4][2];
-
- viconutil_set_point(pts[0], x + 3, y + 3);
- viconutil_set_point(pts[1], x + w - 3, y + 3);
- viconutil_set_point(pts[2], x + w - 3, y + h - 3);
- viconutil_set_point(pts[3], x + 3, y + h - 3);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- viconutil_draw_lineloop(pts, 4);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 4, 1);
-}
-
-static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- viconutil_draw_tri(pts);
-
- glColor4f(0.0, 0.0, 0.0, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(0.9f, 0.9f, 0.9f);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx - d2, cy + d);
- viconutil_set_point(pts[1], cx - d2, cy - d);
- viconutil_set_point(pts[2], cx + d2, cy);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
{
GLint pts[3][2];
@@ -400,63 +233,6 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
glEnd();
}
-static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx + d, cy + d2);
- viconutil_set_point(pts[1], cx - d, cy + d2);
- viconutil_set_point(pts[2], cx, cy - d2);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
-static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = -2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
-
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d + 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = 2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
-
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d - 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
{
/* init dummy theme state for Action Editor - where these colors are defined
@@ -782,15 +558,6 @@ static void init_internal_icons(void)
}
}
- def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw);
- def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_DEHLT, vicon_editmode_dehlt_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_HLT, vicon_editmode_hlt_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw);
- def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw);
- def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw);
- def_internal_vicon(VICO_X_VEC, vicon_x_draw);
def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 5e24dc96255..539284030c2 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -2750,17 +2750,21 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(278, 3)) {
+ for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* Keyframe Indicators (were using wrong alpha) */
+ btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
+ btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
+ }
+ }
+
/**
* Include next version bump.
*
* (keep this block even if it becomes empty).
*/
{
- for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Keyframe Indicators (were using wrong alpha) */
- btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
- btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
- }
+
}
if (U.pixelsize == 0.0f)
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 8659100df87..baae92f962e 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -305,7 +305,6 @@ void WM_OT_collada_export(wmOperatorType *ot)
static EnumPropertyItem prop_bc_export_transformation_type[] = {
{BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"},
{BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"},
- {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use <matrix> AND <translate>, <rotate>, <scale> to specify transformations"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index e31e4096ded..e05ce727e22 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -496,7 +496,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
}
/* face should never exist */
- BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false);
+ BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 7e31deba2c7..c57b0215d46 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1561,6 +1561,18 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
/* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
+ const int tot_failed = tot - tot_rotate;
+ if (tot_failed != 0) {
+ /* If some edges fail to rotate, we need to re-select them,
+ * otherwise we can end up with invalid selection
+ * (unselected edge between 2 selected faces). */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+
+ BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed);
+ }
+
EDBM_selectmode_flush(em);
if (!EDBM_op_finish(em, &bmop, op, true)) {
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 4fc61e0912e..438c3acdb11 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1139,7 +1139,6 @@ BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
{
- BMFace *f_mirr = NULL;
BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
BMLoop *l_iter, *l_first;
@@ -1152,8 +1151,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
}
} while ((l_iter = l_iter->next) != l_first);
- BM_face_exists(v_mirr_arr, f->len, &f_mirr);
- return f_mirr;
+ return BM_face_exists(v_mirr_arr, f->len);
}
void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 9f91feee4c6..8e64cdc9751 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1307,7 +1307,9 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (use_hierarchy || use_base_parent) {
dupli_gh = BLI_ghash_ptr_new(__func__);
- parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+ if (use_hierarchy) {
+ parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+ }
}
for (dob = lb->first; dob; dob = dob->next) {
@@ -1344,10 +1346,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
copy_m4_m4(ob->obmat, dob->mat);
BKE_object_apply_mat4(ob, ob->obmat, false, false);
- if (dupli_gh)
+ if (dupli_gh) {
BLI_ghash_insert(dupli_gh, dob, ob);
- if (parent_gh)
- BLI_ghash_insert(parent_gh, dob, ob);
+ }
+ if (parent_gh) {
+ void **val;
+ /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same',
+ * this avoids trying to insert same key several time and raise asserts in debug builds... */
+ if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) {
+ *val = ob;
+ }
+ }
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d1232fd2aab..f448e925dd9 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1740,10 +1740,16 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
clear_sca_new_poins(); /* sensor/contr/act */
- /* newid may still have some trash from Outliner tree building,
- * so clear that first to avoid errors [#26002] */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
- ob->id.newid = NULL;
+ /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002.
+ * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ for (ID *id = lb->first; id; id = id->next) {
+ id->newid = NULL;
+ }
+ }
/* duplicate (must set newid) */
for (base = FIRSTBASE; base; base = base->next) {
@@ -2235,7 +2241,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
"Orphan library objects added to the current scene to avoid loss");
}
- BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */
+ BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index bd016b7fcfb..56f59dca9a1 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -886,7 +886,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
/* warning, this lookup is _not_ fast */
- if (cd_dvert_offset != -1) {
+ if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
BMVert *eve;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
eve = BM_vert_at_index(em->bm, vertnum);
@@ -2604,6 +2604,8 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "all"))
BKE_object_defgroup_remove_all(ob);
+ else if (RNA_boolean_get(op->ptr, "all_unlocked"))
+ BKE_object_defgroup_remove_all_ex(ob, true);
else
vgroup_delete_active(ob);
@@ -2633,6 +2635,7 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups");
+ RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups");
}
static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 9d9ccf2f3ba..16842efb436 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -315,6 +315,12 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
IMB_freeImBuf(out);
}
+ else if (gpd){
+ /* If there are no strips, Grease Pencil still needs a buffer to draw on */
+ ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
+ RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ IMB_freeImBuf(out);
+ }
if (gpd) {
int i;
@@ -479,23 +485,24 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende
/* copy image data from rectf */
// XXX: Needs conversion.
unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
- float *dest = rp->rect;
-
- int x, y, rectx, recty;
- rectx = rr->rectx;
- recty = rr->recty;
- for (y = 0; y < recty; y++) {
- for (x = 0; x < rectx; x++) {
- unsigned char *pixSrc = src + 4 * (rectx * y + x);
- if (pixSrc[3] > 0) {
- float *pixDest = dest + 4 * (rectx * y + x);
- float float_src[4];
- srgb_to_linearrgb_uchar4(float_src, pixSrc);
- addAlphaOverFloat(pixDest, float_src);
+ if (src != NULL) {
+ float *dest = rp->rect;
+
+ int x, y, rectx, recty;
+ rectx = rr->rectx;
+ recty = rr->recty;
+ for (y = 0; y < recty; y++) {
+ for (x = 0; x < rectx; x++) {
+ unsigned char *pixSrc = src + 4 * (rectx * y + x);
+ if (pixSrc[3] > 0) {
+ float *pixDest = dest + 4 * (rectx * y + x);
+ float float_src[4];
+ srgb_to_linearrgb_uchar4(float_src, pixSrc);
+ addAlphaOverFloat(pixDest, float_src);
+ }
}
}
}
-
/* back layer status */
i = 0;
for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 860a865466a..c69e01422e0 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -442,6 +442,17 @@ int ED_operator_posemode(bContext *C)
return 0;
}
+int ED_operator_posemode_local(bContext *C)
+{
+ if (ED_operator_posemode(C)) {
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ return !(ID_IS_LINKED_DATABLOCK(&ob->id) ||
+ ID_IS_LINKED_DATABLOCK(&arm->id));
+ }
+ return false;
+}
+
/* wrapper for ED_space_image_show_uvedit */
int ED_operator_uvedit(bContext *C)
{
@@ -2136,7 +2147,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
ot->exec = frame_offset_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = 0;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
@@ -2189,7 +2201,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
ot->exec = frame_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
@@ -2295,7 +2308,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
ot->exec = keyframe_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
@@ -2357,7 +2371,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
ot->exec = marker_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index fe0fb3f5035..53434b18d06 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -4688,7 +4688,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_restore_mesh(sd, ob);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
@@ -5406,7 +5406,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
if (!ts->sculpt->detail_percent)
ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
- ts->sculpt->constant_detail = 30.0f;
+ ts->sculpt->constant_detail = 3.0f;
/* Set sane default tiling offsets */
if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f;
@@ -5543,7 +5543,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
size = max_fff(bb_max[0], bb_max[1], bb_max[2]);
/* update topology size */
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
@@ -5608,7 +5608,8 @@ static void sample_detail(bContext *C, int ss_co[2])
ray_start, ray_normal, false);
if (srd.hit) {
- sd->constant_detail = srd.detail * 100.0f;
+ /* convert edge length to detail resolution */
+ sd->constant_detail = 1.0f / srd.detail;
}
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 58c538c4ee5..72de7e5c81c 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -587,6 +587,8 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
last_category = user->category;
}
+
+ UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
}
void uiTemplateTextureUser(uiLayout *layout, bContext *C)
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 6af36ea6778..83469a48165 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2510,7 +2510,7 @@ static void filelist_readjob_do(
* Using an atomic operation to avoid having to lock thread...
* Note that we do not really need this here currently, since there is a single listing thread, but better
* remain consistent about threading! */
- *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
+ *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
/* Only thing we change in direntry here, so we need to free it first. */
MEM_freeN(entry->relpath);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index ea40d4eb5e1..dd282c427f6 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -7915,10 +7915,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (!render_override && sds->draw_velocity) {
draw_smoke_velocity(sds, viewnormal);
}
-
-#ifdef SMOKE_DEBUG_HEAT
- draw_smoke_heat(smd->domain, ob);
-#endif
}
}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index b0e21601b9c..27ecbf83db5 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_texture.h"
#include "BKE_particle.h"
#include "smoke_API.h"
@@ -62,28 +63,33 @@ struct GPUTexture;
# include "PIL_time_utildefines.h"
#endif
-static GPUTexture *create_flame_spectrum_texture(void)
+/* *************************** Transfer functions *************************** */
+
+enum {
+ TFUNC_FLAME_SPECTRUM = 0,
+ TFUNC_COLOR_RAMP = 1,
+};
+
+#define TFUNC_WIDTH 256
+
+static void create_flame_spectrum_texture(float *data)
{
-#define SPEC_WIDTH 256
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
- GPUTexture *tex;
- int i, j, k;
- float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data");
- float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+ float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
- blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000);
+ blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
- for (i = 0; i < 16; i++) {
- for (j = 0; j < 16; j++) {
- for (k = 0; k < SPEC_WIDTH; k++) {
- int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ for (int k = 0; k < TFUNC_WIDTH; k++) {
+ int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
if (k >= FIRE_THRESH) {
- spec_pixels[index] = (spec_data[k * 4]);
- spec_pixels[index + 1] = (spec_data[k * 4 + 1]);
- spec_pixels[index + 2] = (spec_data[k * 4 + 2]);
+ spec_pixels[index] = (data[k * 4]);
+ spec_pixels[index + 1] = (data[k * 4 + 1]);
+ spec_pixels[index + 2] = (data[k * 4 + 2]);
spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
(k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
}
@@ -94,19 +100,69 @@ static GPUTexture *create_flame_spectrum_texture(void)
}
}
- tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
+ memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
- MEM_freeN(spec_data);
MEM_freeN(spec_pixels);
-#undef SPEC_WIDTH
#undef FIRE_THRESH
#undef MAX_FIRE_ALPHA
#undef FULL_ON_FIRE
+}
+
+static void create_color_ramp(const ColorBand *coba, float *data)
+{
+ for (int i = 0; i < TFUNC_WIDTH; i++) {
+ do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
+ }
+}
+
+static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
+{
+ float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
+
+ switch (type) {
+ case TFUNC_FLAME_SPECTRUM:
+ create_flame_spectrum_texture(data);
+ break;
+ case TFUNC_COLOR_RAMP:
+ create_color_ramp(coba, data);
+ break;
+ }
+
+ GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL);
+
+ MEM_freeN(data);
return tex;
}
+static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
+{
+ float *field = NULL;
+
+ switch (sds->coba_field) {
+#ifdef WITH_SMOKE
+ case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break;
+ case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break;
+ case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break;
+ case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break;
+ case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
+ case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break;
+ case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break;
+ case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break;
+ case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break;
+ case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break;
+ case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break;
+#endif
+ default: return NULL;
+ }
+
+ return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field);
+}
+
typedef struct VolumeSlicer {
float size[3];
float min[3];
@@ -347,6 +403,7 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
}
static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
+ GPUTexture *tex_tfunc, GPUTexture *tex_coba,
bool use_fire, const float min[3],
const float ob_sizei[3], const float invsize[3])
{
@@ -359,6 +416,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
int densityscale_location;
int spec_location, flame_location;
int shadow_location, actcol_location;
+ int tfunc_location = 0;
+ int coba_location = 0;
if (use_fire) {
spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
@@ -370,6 +429,11 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
soot_location = GPU_shader_get_uniform(shader, "soot_texture");
stepsize_location = GPU_shader_get_uniform(shader, "step_size");
densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
+
+ if (sds->use_coba) {
+ tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture");
+ coba_location = GPU_shader_get_uniform(shader, "color_band_texture");
+ }
}
GPU_shader_bind(shader);
@@ -397,6 +461,14 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
mul_v3_v3(active_color, sds->active_color);
GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
+
+ if (sds->use_coba) {
+ GPU_texture_bind(tex_tfunc, 4);
+ GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc);
+
+ GPU_texture_bind(tex_coba, 5);
+ GPU_shader_uniform_texture(shader, coba_location, tex_coba);
+ }
}
GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
@@ -404,7 +476,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture
GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
}
-static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire)
+static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec,
+ GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire)
{
GPU_shader_unbind();
@@ -417,20 +490,30 @@ static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool u
}
else {
GPU_texture_unbind(sds->tex_shadow);
+
+ if (sds->use_coba) {
+ GPU_texture_unbind(tex_tfunc);
+ GPU_texture_free(tex_tfunc);
+
+ GPU_texture_unbind(tex_coba);
+ GPU_texture_free(tex_coba);
+ }
}
}
static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
{
- GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL;
+ GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL;
+ GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL;
+ GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL;
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
- bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize);
+ bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, NULL);
@@ -439,7 +522,7 @@ static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const Volum
glDisableClientState(GL_VERTEX_ARRAY);
- unbind_shader(sds, tex_spec, do_fire);
+ unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire);
/* cleanup */
@@ -459,7 +542,16 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE);
+ GPUBuiltinShader builtin_shader;
+
+ if (sds->use_coba) {
+ builtin_shader = GPU_SHADER_SMOKE_COBA;
+ }
+ else {
+ builtin_shader = GPU_SHADER_SMOKE;
+ }
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader);
if (!shader) {
fprintf(stderr, "Unable to create GLSL smoke shader.\n");
@@ -549,7 +641,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
/* Draw fire separately (T47639). */
- if (use_fire) {
+ if (use_fire && !sds->use_coba) {
glBlendFunc(GL_ONE, GL_ONE);
draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
}
@@ -759,50 +851,3 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
UNUSED_VARS(domain, viewnormal);
#endif
}
-
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
-{
- float x, y, z;
- float x0, y0, z0;
- int *base_res = domain->base_res;
- int *res = domain->res;
- int *res_min = domain->res_min;
- int *res_max = domain->res_max;
- float *heat = smoke_get_heat(domain->fluid);
-
- float min[3];
- float *cell_size = domain->cell_size;
- float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
- float vf = domain->scale / 16.f * 2.f; /* velocity factor */
-
- /* set first position so that it doesn't jump when domain moves */
- x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
- y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
- z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
- if (x0 < res_min[0]) x0 += step_size;
- if (y0 < res_min[1]) y0 += step_size;
- if (z0 < res_min[2]) z0 += step_size;
- add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
-
- for (x = floor(x0); x < res_max[0]; x += step_size)
- for (y = floor(y0); y < res_max[1]; y += step_size)
- for (z = floor(z0); z < res_max[2]; z += step_size) {
- int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
-
- float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
-
- /* draw heat as different sized points */
- if (heat[index] >= 0.01f) {
- float col_gb = 1.0f - heat[index];
- CLAMP(col_gb, 0.0f, 1.0f);
- glColor3f(1.0f, col_gb, col_gb);
- glPointSize(24.0f * heat[index]);
-
- glBegin(GL_POINTS);
- glVertex3f(pos[0], pos[1], pos[2]);
- glEnd();
- }
- }
-}
-#endif
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 0e2cb95dd89..b11f42bcfef 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -296,14 +296,8 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
const float viewnormal[3]);
-//#define SMOKE_DEBUG_HEAT
-
void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]);
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
-#endif
-
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
* without this define we get the old behavior which is to try and align them
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ef6cff19181..daf0aed59e7 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -3392,7 +3392,9 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
}
protectedTransBits(td->protectflag, vec);
- add_v3_v3v3(td->loc, td->iloc, vec);
+ if (td->loc) {
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
constraintTransLim(t, td);
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 9c266890d6d..ce3d903b8f6 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5583,7 +5583,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (tmode == TFM_TRANSLATION) {
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (v3d->around == V3D_AROUND_ACTIVE) {
if (ob != OBACT)
do_loc = true;
@@ -5728,7 +5728,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
else
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
do_loc = true;
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index ee6700666c0..4a9311416b3 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -217,6 +217,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
return OPERATOR_FINISHED;
}
+void ED_undo_grouped_push(bContext *C, const char *str)
+{
+ /* do nothing if previous undo task is the same as this one (or from the same undo group) */
+ const char *last_undo = BKE_undo_get_name_last();
+
+ if (last_undo && STREQ(str, last_undo)) {
+ return;
+ }
+
+ /* push as usual */
+ ED_undo_push(C, str);
+}
+
void ED_undo_pop(bContext *C)
{
ed_undo_step(C, 1, NULL);
@@ -232,6 +245,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op)
ED_undo_push(C, op->type->name);
}
+void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
+{
+ if (op->type->undo_group[0] != '\0') {
+ ED_undo_grouped_push(C, op->type->undo_group);
+ }
+ else {
+ ED_undo_grouped_push(C, op->type->name);
+ }
+}
+
void ED_undo_pop_op(bContext *C, wmOperator *op)
{
/* search back a couple of undo's, in case something else added pushes */
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 762329ee077..5b94db6e120 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -89,6 +89,7 @@ typedef enum GPUBuiltinShader {
GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
GPU_SHADER_SMOKE = 2,
GPU_SHADER_SMOKE_FIRE = 3,
+ GPU_SHADER_SMOKE_COBA = 4,
} GPUBuiltinShader;
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 5cfb323bc4b..14f2764b009 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -68,6 +68,7 @@ static struct GPUShadersGlobal {
GPUShader *sep_gaussian_blur;
GPUShader *smoke;
GPUShader *smoke_fire;
+ GPUShader *smoke_coba;
/* cache for shader fx. Those can exist in combinations so store them here */
GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
} shaders;
@@ -623,6 +624,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.smoke_fire;
break;
+ case GPU_SHADER_SMOKE_COBA:
+ if (!GG.shaders.smoke_coba)
+ GG.shaders.smoke_coba = GPU_shader_create(
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
+ NULL, NULL, "#define USE_COBA;\n", 0, 0, 0);
+ retval = GG.shaders.smoke_coba;
+ break;
}
if (retval == NULL)
@@ -734,6 +742,11 @@ void GPU_shader_free_builtin_shaders(void)
GG.shaders.smoke_fire = NULL;
}
+ if (GG.shaders.smoke_coba) {
+ GPU_shader_free(GG.shaders.smoke_coba);
+ GG.shaders.smoke_coba = NULL;
+ }
+
for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) {
if (GG.shaders.fx_shaders[i]) {
GPU_shader_free(GG.shaders.fx_shaders[i]);
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 67da8201f66..4416b6494f9 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2822,7 +2822,7 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
}
#ifdef BIT_OPERATIONS
-vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
+vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias,
float brick_width, float row_height,
float offset_amount, int offset_frequency,
float squash_amount, int squash_frequency)
@@ -2843,17 +2843,26 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
x = (p.x + offset) - brick_width * bricknum;
y = p.y - row_height * rownum;
- return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
- (x < mortar_size || y < mortar_size ||
- x > (brick_width - mortar_size) ||
- y > (row_height - mortar_size)) ? 1.0 : 0.0);
+ float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
+
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+ if(min_dist >= mortar_size) {
+ return vec2(tint, 0.0);
+ }
+ else if(mortar_smooth == 0.0) {
+ return vec2(tint, 1.0);
+ }
+ else {
+ min_dist = 1.0 - min_dist/mortar_size;
+ return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
+ }
}
#endif
void node_tex_brick(vec3 co,
vec4 color1, vec4 color2,
vec4 mortar, float scale,
- float mortar_size, float bias,
+ float mortar_size, float mortar_smooth, float bias,
float brick_width, float row_height,
float offset_amount, float offset_frequency,
float squash_amount, float squash_frequency,
@@ -2861,7 +2870,7 @@ void node_tex_brick(vec3 co,
{
#ifdef BIT_OPERATIONS
vec2 f2 = calc_brick_texture(co * scale,
- mortar_size, bias,
+ mortar_size, mortar_smooth, bias,
brick_width, row_height,
offset_amount, int(offset_frequency),
squash_amount, int(squash_frequency));
@@ -2871,7 +2880,7 @@ void node_tex_brick(vec3 co,
float facm = 1.0 - tint;
color1 = facm * color1 + tint * color2;
}
- color = (f == 1.0) ? mortar : color1;
+ color = mix(color1, mortar, f);
fac = f;
#else
color = vec4(1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
index fd790009e02..6ded453225e 100644
--- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -8,10 +8,17 @@ uniform float density_scale;
uniform sampler3D soot_texture;
uniform sampler3D shadow_texture;
+#ifdef USE_COBA
+uniform sampler1D transfer_texture;
+uniform sampler3D color_band_texture;
+#endif
+
void main()
{
/* compute color and density from volume texture */
vec4 soot = texture3D(soot_texture, coords);
+
+#ifndef USE_COBA
vec3 soot_color;
if (soot.a != 0) {
soot_color = active_color * soot.rgb / soot.a;
@@ -31,6 +38,11 @@ void main()
/* premultiply alpha */
vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
+#else
+ float color_band = texture3D(color_band_texture, coords).r;
+ vec4 transfer_function = texture1D(transfer_texture, color_band);
+ vec4 color = transfer_function * density_scale;
+#endif
gl_FragColor = color;
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index b8ed780397f..d58340965a7 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1763,20 +1763,15 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
}
// if at least one tree, create the scenes from the PoseTree stored in the channels
// postpone until execute_tree: this way the pose constraint are included
- //if (count)
- // create_scene(scene, ob, ctime);
- //itasc_update_param(ob->pose);
+ if (count)
+ create_scene(scene, ob, ctime);
+ itasc_update_param(ob->pose);
// make sure we don't rebuilt until the user changes something important
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- if (!ob->pose->ikdata) {
- // IK tree not yet created, no it now
- create_scene(scene, ob, ctime);
- itasc_update_param(ob->pose);
- }
if (ob->pose->ikdata) {
IK_Data *ikdata = (IK_Data *)ob->pose->ikdata;
bItasc *ikparam = (bItasc *) ob->pose->ikparam;
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index 5d76ffe57b5..381ee5d40e5 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -226,10 +226,16 @@ typedef struct RigidBodyCon {
float spring_stiffness_x;
float spring_stiffness_y;
float spring_stiffness_z;
+ float spring_stiffness_ang_x;
+ float spring_stiffness_ang_y;
+ float spring_stiffness_ang_z;
/* amount of velocity lost over time */
float spring_damping_x;
float spring_damping_y;
float spring_damping_z;
+ float spring_damping_ang_x;
+ float spring_damping_ang_y;
+ float spring_damping_ang_z;
/* motor settings */
float motor_lin_target_velocity; /* linear velocity the motor tries to hold */
@@ -295,7 +301,11 @@ typedef enum eRigidBodyCon_Flag {
RBC_FLAG_USE_SPRING_Z = (1 << 13),
/* motors */
RBC_FLAG_USE_MOTOR_LIN = (1 << 14),
- RBC_FLAG_USE_MOTOR_ANG = (1 << 15)
+ RBC_FLAG_USE_MOTOR_ANG = (1 << 15),
+ /* angular springs */
+ RBC_FLAG_USE_SPRING_ANG_X = (1 << 16),
+ RBC_FLAG_USE_SPRING_ANG_Y = (1 << 17),
+ RBC_FLAG_USE_SPRING_ANG_Z = (1 << 18)
} eRigidBodyCon_Flag;
/* ******************************** */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 9b0781ebe70..f5e71ae59a9 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1103,7 +1103,7 @@ typedef struct Sculpt {
float gravity_factor;
/* scale for constant detail size */
- float constant_detail;
+ float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */
float detail_percent;
float pad;
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 8f197c8c42c..fb81e2b6402 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -77,6 +77,23 @@ enum {
VECTOR_DRAW_STREAMLINE = 1,
};
+enum {
+ FLUID_FIELD_DENSITY = 0,
+ FLUID_FIELD_HEAT = 1,
+ FLUID_FIELD_FUEL = 2,
+ FLUID_FIELD_REACT = 3,
+ FLUID_FIELD_FLAME = 4,
+ FLUID_FIELD_VELOCITY_X = 5,
+ FLUID_FIELD_VELOCITY_Y = 6,
+ FLUID_FIELD_VELOCITY_Z = 7,
+ FLUID_FIELD_COLOR_R = 8,
+ FLUID_FIELD_COLOR_G = 9,
+ FLUID_FIELD_COLOR_B = 10,
+ FLUID_FIELD_FORCE_X = 11,
+ FLUID_FIELD_FORCE_Y = 12,
+ FLUID_FIELD_FORCE_Z = 13,
+};
+
/* cache compression */
#define SM_CACHE_LIGHT 0
#define SM_CACHE_HEAVY 1
@@ -193,9 +210,13 @@ typedef struct SmokeDomainSettings {
float slice_per_voxel;
float slice_depth;
float display_thickness;
+
+ struct ColorBand *coba;
float vector_scale;
char vector_draw_type;
- char pad2[3];
+ char use_coba;
+ char coba_field; /* simulation field used for the color mapping */
+ char pad2;
char cache_filename[1024];
} SmokeDomainSettings;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 280ad4aa9b1..5174c957834 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -35,6 +35,7 @@
#include "BLI_utildefines.h"
#include "BKE_icons.h"
+#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -347,6 +348,20 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
}
}
+static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy)
+{
+ /* Special case, as we can't rely on id_make_local(); it clears proxies. */
+ if (!clear_proxy && GS(self->name) == ID_OB) {
+ BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy);
+ }
+ else {
+ id_make_local(bmain, self, false, false);
+ }
+
+ return self->newid ? self->newid : self;
+}
+
+
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
@@ -999,6 +1014,17 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ func = RNA_def_function(srna, "make_local", "rna_ID_make_local");
+ RNA_def_function_ui_description(func, "Make this datablock local, return local one "
+ "(may be a copy of the original, in case it is also indirectly used)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_boolean(func, "clear_proxy", true, "",
+ "Whether to clear proxies (the default behavior); can cause proxies to be duplicated"
+ " when still referred to from another library");
+ RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL);
+ parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index cc290eab59d..594c1752328 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -585,7 +585,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this camera before deleting it "
"(WARNING: will also delete objects instancing that camera data)");
@@ -624,7 +624,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -665,7 +665,7 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -702,7 +702,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -746,7 +746,7 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -805,7 +805,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this mesh before deleting it "
"(WARNING: will also delete objects instancing that mesh data)");
@@ -845,7 +845,7 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lamp before deleting it "
"(WARNING: will also delete objects instancing that lamp data)");
@@ -963,7 +963,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1000,7 +1000,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lattice before deleting it "
"(WARNING: will also delete objects instancing that lattice data)");
@@ -1040,7 +1040,7 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this curve before deleting it "
"(WARNING: will also delete objects instancing that curve data)");
@@ -1078,7 +1078,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this metaball before deleting it "
"(WARNING: will also delete objects instancing that metaball data)");
@@ -1118,7 +1118,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1156,7 +1156,7 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1193,7 +1193,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1230,7 +1230,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1267,7 +1267,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1304,7 +1304,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this speaker before deleting it "
"(WARNING: will also delete objects instancing that speaker data)");
@@ -1343,7 +1343,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
@@ -1393,7 +1393,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1430,7 +1430,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this armature before deleting it "
"(WARNING: will also delete objects instancing that armature data)");
@@ -1468,7 +1468,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1504,7 +1504,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them");
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1540,7 +1540,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1610,7 +1610,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1639,7 +1639,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1691,7 +1691,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1728,7 +1728,7 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index bdf001ed0e1..85a34a94746 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -507,6 +507,45 @@ static void rna_RigidBodyCon_spring_stiffness_z_set(PointerRNA *ptr, float value
#endif
}
+static void rna_RigidBodyCon_spring_stiffness_ang_x_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_x = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_stiffness_ang_y_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_y = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_stiffness_ang_z_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_z = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value);
+ }
+#endif
+}
+
static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value)
{
RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
@@ -544,6 +583,43 @@ static void rna_RigidBodyCon_spring_damping_z_set(PointerRNA *ptr, float value)
#endif
}
+static void rna_RigidBodyCon_spring_damping_ang_x_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_x = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_damping_ang_y_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_y = value;
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_damping_ang_z_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_z = value;
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value);
+ }
+#endif
+}
+
static void rna_RigidBodyCon_motor_lin_max_impulse_set(PointerRNA *ptr, float value)
{
RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
@@ -1061,6 +1137,21 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Z Spring", "Enable spring on Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "use_spring_ang_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_X);
+ RNA_def_property_ui_text(prop, "X Angle Spring", "Enable spring on X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "use_spring_ang_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Y);
+ RNA_def_property_ui_text(prop, "Y Angle Spring", "Enable spring on Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "use_spring_ang_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Z);
+ RNA_def_property_ui_text(prop, "Z Angle Spring", "Enable spring on Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set");
@@ -1178,6 +1269,33 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Z Axis Stiffness", "Stiffness on the Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "spring_stiffness_ang_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_x");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_x_set", NULL);
+ RNA_def_property_ui_text(prop, "X Angle Stiffness", "Stiffness on the X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_stiffness_ang_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_y");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_y_set", NULL);
+ RNA_def_property_ui_text(prop, "Y Angle Stiffness", "Stiffness on the Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_stiffness_ang_z", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_z");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_z_set", NULL);
+ RNA_def_property_ui_text(prop, "Z Angle Stiffness", "Stiffness on the Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_x");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1202,6 +1320,30 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Damping Z", "Damping on the Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_x_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping X Angle", "Damping on the X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_y_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping Y Angle", "Damping on the Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_z_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping Z Angle", "Damping on the Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "motor_lin_target_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY);
RNA_def_property_float_sdna(prop, NULL, "motor_lin_target_velocity");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index e169ef0d822..7f405f0fb1f 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -600,10 +600,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)");
+ prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "constant_detail");
+ RNA_def_property_range(prop, 0.0001, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Resolution", "Maximum edge length for dynamic topology sculpting (as divisor "
+ "of blender unit - higher value means smaller edge length)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index ce18c86b8d0..15950e67671 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -30,6 +30,7 @@
#include <limits.h>
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
@@ -53,6 +54,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_particle.h"
+#include "BKE_texture.h"
#include "smoke_API.h"
@@ -383,13 +385,24 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
}
+static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value)
+{
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+
+ sds->use_coba = value;
+
+ if (value && sds->coba == NULL) {
+ sds->coba = add_colorband(false);
+ }
+}
+
static void rna_SmokeModifier_cache_filename_get(PointerRNA *ptr, char *filename)
{
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- PTCacheID pid;
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ PTCacheID pid;
- BKE_ptcache_id_from_smoke(&pid, ptr->id.data, sds->smd);
- ptcache_filename(&pid, filename, sds->smd->time, 1, 1);
+ BKE_ptcache_id_from_smoke(&pid, ptr->id.data, sds->smd);
+ ptcache_filename(&pid, filename, sds->smd->time, 1, 1);
}
#else
@@ -815,6 +828,41 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ /* --------- Color mapping. --------- */
+
+ prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set");
+ RNA_def_property_ui_text(prop, "Use Color Ramp",
+ "Render a simulation field while mapping its voxels values to the colors of a ramp");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ static EnumPropertyItem coba_field_items[] = {
+ {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
+ {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
+ {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
+ {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+ {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
+ {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
+ {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
+ {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
+ {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
+ {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "coba_field");
+ RNA_def_property_enum_items(prop, coba_field_items);
+ RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "coba");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Color Ramp", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
prop = RNA_def_property(srna, "cache_filename", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 1024);
RNA_def_property_string_funcs(prop, "rna_SmokeModifier_cache_filename_get", NULL, NULL);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index ffcf12edb2d..b262e6412e3 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1980,7 +1980,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
static EnumPropertyItem other_uv_filter_items[] = {
{SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"},
{SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image",
- "Only show others' UV islads who's active image matches image of the active face"},
+ "Only show others' UV islands whose active image matches image of the active face"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 8ad016007f4..10807c32b91 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -52,15 +52,6 @@
#include "BLT_lang.h"
#include "GPU_buffers.h"
-#ifdef WITH_CYCLES
-static EnumPropertyItem compute_device_type_items[] = {
- {USER_COMPUTE_DEVICE_NONE, "NONE", 0, "None", "Don't use compute device"},
- {USER_COMPUTE_DEVICE_CUDA, "CUDA", 0, "CUDA", "Use CUDA for GPU acceleration"},
- {USER_COMPUTE_DEVICE_OPENCL, "OPENCL", 0, "OpenCL", "Use OpenCL for GPU acceleration"},
- { 0, NULL, 0, NULL, NULL}
-};
-#endif
-
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem opensubdiv_compute_type_items[] = {
{USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""},
@@ -124,8 +115,6 @@ static EnumPropertyItem rna_enum_language_default_items[] = {
#include "UI_interface.h"
-#include "CCL_api.h"
-
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
#endif
@@ -476,78 +465,6 @@ static PointerRNA rna_Theme_space_list_generic_get(PointerRNA *ptr)
}
-#ifdef WITH_CYCLES
-static EnumPropertyItem *rna_userdef_compute_device_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- /* add supported device types */
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_NONE);
- if (CCL_compute_device_list(0))
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_CUDA);
- if (CCL_compute_device_list(1))
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_OPENCL);
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static int rna_userdef_compute_device_get(PointerRNA *UNUSED(ptr))
-{
- if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE)
- return 0;
-
- return U.compute_device_id;
-}
-
-static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) {
- /* only add a single CPU device */
- tmp.value = 0;
- tmp.name = "CPU";
- tmp.identifier = "CPU";
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- else {
- /* get device list from cycles. it would be good to make this generic
- * once we have more subsystems using opencl, for now this is easiest */
- int opencl = (U.compute_device_type == USER_COMPUTE_DEVICE_OPENCL);
- CCLDeviceInfo *devices = CCL_compute_device_list(opencl);
- int a;
-
- if (devices) {
- for (a = 0; devices[a].identifier[0]; a++) {
- tmp.value = devices[a].value;
- tmp.identifier = devices[a].identifier;
- tmp.name = devices[a].name;
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- }
- else {
- tmp.value = 0;
- tmp.name = "CPU";
- tmp.identifier = "CPU";
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-#endif
-
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
@@ -3977,13 +3894,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
-#ifdef WITH_CYCLES
- static EnumPropertyItem compute_device_items[] = {
- {0, "CPU", 0, "CPU", ""},
- { 0, NULL, 0, NULL, NULL}
- };
-#endif
-
static EnumPropertyItem image_draw_methods[] = {
{IMAGE_DRAW_METHOD_2DTEXTURE, "2DTEXTURE", 0, "2D Texture", "Use CPU for display transform and draw image with 2D texture"},
{IMAGE_DRAW_METHOD_GLSL, "GLSL", 0, "GLSL", "Use GLSL shaders for display transform and draw image with 2D texture"},
@@ -4275,23 +4185,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Draw tool/property regions over the main region, when using Triple Buffer");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-#ifdef WITH_CYCLES
- prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
- RNA_def_property_enum_sdna(prop, NULL, "compute_device_type");
- RNA_def_property_enum_items(prop, compute_device_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_compute_device_type_itemf");
- RNA_def_property_ui_text(prop, "Compute Device Type", "Device to use for computation (rendering with Cycles)");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
-
- prop = RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
- RNA_def_property_enum_sdna(prop, NULL, "compute_device_id");
- RNA_def_property_enum_items(prop, compute_device_items);
- RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf");
- RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation");
-#endif
-
#ifdef WITH_OPENSUBDIV
prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 90081a93188..35c9c9bcc89 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = {
static EnumPropertyItem operator_flag_items[] = {
{OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"},
{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
+ {OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
{OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
@@ -1139,6 +1140,7 @@ static char _operator_idname[OP_MAX_TYPENAME];
static char _operator_name[OP_MAX_TYPENAME];
static char _operator_descr[RNA_DYN_DESCR_MAX];
static char _operator_ctxt[RNA_DYN_DESCR_MAX];
+static char _operator_undo_group[OP_MAX_TYPENAME];
static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
@@ -1153,10 +1155,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1210,9 +1213,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
int namelen = strlen(_operator_name) + 1;
int desclen = strlen(_operator_descr) + 1;
int ctxtlen = strlen(_operator_ctxt) + 1;
+ int ugrouplen = strlen(_operator_undo_group) + 1;
char *ch;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+ ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idlen;
@@ -1224,6 +1228,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
ch += desclen;
strcpy(ch, _operator_ctxt);
dummyot.translation_context = ch;
+ ch += ctxtlen;
+ strcpy(ch, _operator_undo_group);
+ dummyot.undo_group = ch;
}
}
@@ -1280,10 +1287,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1297,9 +1305,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
int namelen = strlen(_operator_name) + 1;
int desclen = strlen(_operator_descr) + 1;
int ctxtlen = strlen(_operator_ctxt) + 1;
+ int ugrouplen = strlen(_operator_undo_group) + 1;
char *ch;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+ ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idlen;
@@ -1311,6 +1320,9 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
ch += desclen;
strcpy(ch, _operator_ctxt);
dummyot.translation_context = ch;
+ ch += ctxtlen;
+ strcpy(ch, _operator_undo_group);
+ dummyot.undo_group = ch;
}
if (strlen(identifier) >= sizeof(dummyop.idname)) {
@@ -1401,6 +1413,16 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value)
assert(!"setting the bl_description on a non-builtin operator");
}
+static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value)
+{
+ wmOperator *data = (wmOperator *)(ptr->data);
+ char *str = (char *)data->type->undo_group;
+ if (!str[0])
+ BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_undo_group on a non-builtin operator");
+}
+
static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
@@ -1509,6 +1531,14 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
@@ -1587,6 +1617,14 @@ static void rna_def_macro_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index ecbc3891e8c..b049457e640 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -143,17 +143,17 @@ static void updateDepsgraph(ModifierData *md,
{
ArrayModifierData *amd = (ArrayModifierData *)md;
if (amd->start_cap != NULL) {
- DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
}
if (amd->end_cap != NULL) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
}
if (amd->curve_ob) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
+ DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
- DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
+ DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
}
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 83c4ca7984c..9186b10d8ca 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -145,12 +145,9 @@ static void updateDepsgraph(ModifierData *md,
HookModifierData *hmd = (HookModifierData *)md;
if (hmd->object != NULL) {
if (hmd->subtarget[0]) {
- DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
}
- else {
- DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
- }
+ DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
/* We need own transformation as well. */
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 1d951bae48b..b20c03bee28 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -2233,7 +2233,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
}
/* check if the face exists */
- if (BM_face_exists(vert_array, vert_seq_len, NULL)) {
+ if (BM_face_exists(vert_array, vert_seq_len) != NULL) {
PyErr_SetString(PyExc_ValueError,
"faces.new(verts): face already exists");
goto cleanup;
@@ -2426,7 +2426,8 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
return NULL;
}
- if (BM_face_exists(vert_array, vert_seq_len, &f)) {
+ f = BM_face_exists(vert_array, vert_seq_len);
+ if (f != NULL) {
ret = BPy_BMFace_CreatePyObject(bm, f);
}
else {
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index ec69abbb1df..15f3c665fcf 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -33,6 +33,7 @@
#include <stddef.h>
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_string.h"
#include "BLI_linklist.h"
#include "BLI_path_util.h"
@@ -405,6 +406,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BLO_blendhandle_close(self->blo_handle);
self->blo_handle = NULL;
+ GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+
/* copied from wm_operator.c */
{
/* mark all library linked objects to be updated */
@@ -412,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* append, rather than linking */
if ((self->flag & FILE_LINK) == 0) {
- BKE_library_make_local(bmain, lib, true, false);
+ BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
}
}
@@ -439,6 +442,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
ID *id;
id = PyCapsule_GetPointer(item, NULL);
+ id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
Py_DECREF(item);
RNA_id_pointer_create(id, &id_ptr);
@@ -452,6 +456,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
#endif /* USE_RNA_DATABLOCKS */
+ BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 9dec2698720..3d6462e09a0 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -2064,11 +2064,13 @@ static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[
if (lar->mode & LA_SHAD_TEX)
do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+ if (R.r.mode & R_SHADOW) {
+ lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
- shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
- shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
- shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
+ shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
+ shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
+ shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
+ }
}
return visifac;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 0fe3e8a0fcf..cd46e24264d 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -138,6 +138,7 @@ enum {
OPTYPE_INTERNAL = (1 << 6),
OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */
+ OPTYPE_UNDO_GROUPED = (1 << 8), /* Special type of undo which doesn't store itself multiple times */
};
/* context to call operator in for WM_operator_name_call */
@@ -522,6 +523,7 @@ typedef struct wmOperatorType {
const char *idname; /* unique identifier */
const char *translation_context;
const char *description; /* tooltips and python docs */
+ const char *undo_group; /* identifier to group operators together */
/* this callback executes the operator without any interactive input,
* parameters may be provided through operator properties. cannot use
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index dc34e8015c9..d2b0acd836b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -727,10 +727,13 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
/* we don't want to do undo pushes for operators that are being
* called from operators that already do an undo push. usually
* this will happen for python operators that call C operators */
- if (wm->op_undo_depth == 0)
+ if (wm->op_undo_depth == 0) {
if (op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, op);
-
+ else if (op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, op);
+ }
+
if (repeat == 0) {
if (G.debug & G_DEBUG_WM) {
char *buf = WM_operator_pystring(C, op, false, true);
@@ -1854,9 +1857,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
wm->op_undo_depth--;
/* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
- if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
+ if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
if (handler->op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, handler->op);
+ else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, handler->op);
+ }
if (handler->op->reports->list.first) {
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index e872ec1a524..3b733f9558c 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -419,7 +419,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
if (use_recursive) {
- BKE_library_make_local(bmain, NULL, true, set_fake);
+ BKE_library_make_local(bmain, NULL, NULL, true, set_fake);
}
else {
LinkNode *itemlink;
@@ -430,7 +430,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id;
if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) {
- BKE_library_make_local(bmain, new_id->lib, true, set_fake);
+ BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake);
BLI_gset_insert(done_libraries, new_id->lib);
}
}
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index d8a4ddc8d4f..6040dfff644 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -142,7 +142,6 @@ struct wmWindowManager;
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-#include "../../intern/cycles/blender/CCL_api.h"
#include "../../intern/dualcon/dualcon.h"
#include "../../intern/elbeem/extern/elbeem.h"
#include "../blender/blenkernel/BKE_modifier.h"
@@ -770,10 +769,6 @@ void *dualcon(const DualConInput *input_mesh,
float scale,
int depth) RET_ZERO
-/* intern/cycles */
-struct CCLDeviceInfo;
-struct CCLDeviceInfo *CCL_compute_device_list(int opencl) RET_NULL
-
/* compositor */
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index f65688e1304..10af0d5489e 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -1153,13 +1153,12 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
COMPONENT Blender
DESTINATION "."
)
-
+ if(CMAKE_CL_64)
+ set(_WIN_PLATFORM x64)
+ else()
+ set(_WIN_PLATFORM x86)
+ endif()
if(MSVC12_REDIST_DIR)
- if(CMAKE_CL_64)
- set(_WIN_PLATFORM x64)
- else()
- set(_WIN_PLATFORM x86)
- endif()
install(
FILES
${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll
@@ -1173,4 +1172,51 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
)
endif()
endif()
+
+ if(MSVC14_REDIST_DIR)
+ set(KITSDIRx86 "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/")
+ set(KITSDIR "$ENV{ProgramFiles}/Windows Kits/10/")
+ if(IS_DIRECTORY ${KITSDIR})
+ set(KITSPATH "${KITSDIR}/Redist/ucrt/DLLs/${_WIN_PLATFORM}")
+ else()
+ if(IS_DIRECTORY ${KITSDIRx86})
+ set(KITSPATH "${KITSDIRx86}/Redist/ucrt/DLLs/${_WIN_PLATFORM}")
+ else()
+ message(FATAL_ERROR "Windows 10 SDK directory not found")
+ endif()
+ endif()
+
+ install(
+ FILES
+ ${KITSPATH}/api-ms-win-core-file-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-file-l2-1-0.dll
+ ${KITSPATH}/api-ms-win-core-localization-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-processthreads-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-core-processthreads-l1-1-1.dll
+ ${KITSPATH}/api-ms-win-core-synch-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-core-synch-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-timezone-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-conio-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-convert-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-environment-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-filesystem-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-heap-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-locale-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-math-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-process-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-runtime-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-stdio-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-string-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-time-l1-1-0.dll
+ ${KITSPATH}/ucrtbase.dll
+ ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.CRT/vcruntime140.dll
+ DESTINATION "."
+ )
+ if(WITH_OPENMP)
+ install(
+ FILES ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.OpenMP/vcomp140.dll
+ DESTINATION "."
+ )
+ endif()
+ endif()
endif()
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
index 4f5e34896fc..c588a4b33cf 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.cpp
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -544,12 +544,12 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/,
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
{
- return atomic_add_uint32(&mRefCount, 1U);
+ return atomic_add_and_fetch_uint32(&mRefCount, 1U);
}
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
{
- uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
+ uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U);
if (newCount == 0)
delete this;
return (ULONG)newCount;