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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2018-04-11 18:08:25 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2018-04-11 18:08:25 +0300
commit8e44c30d7176ecb9da06948ae66d5aa9dbd3a85f (patch)
tree7fbb35e32b9067ad513d5faf82d723a2cf4d736e
parentb4c057f42faa81d490bf785272cce27bc7acc0b9 (diff)
parent8aa6e4d50bfcc0d83985f783228408586b0f877b (diff)
Merge branch 'master' into soc-2017-normal-tools
-rw-r--r--CMakeLists.txt6
-rw-r--r--build_files/build_environment/cmake/openal.cmake1
-rw-r--r--build_files/build_environment/cmake/openimageio.cmake1
-rw-r--r--build_files/cmake/macros.cmake4
-rw-r--r--doc/doxygen/doxygen.source.h4
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp19
-rw-r--r--intern/clog/clog.c3
-rw-r--r--intern/cycles/CMakeLists.txt48
-rw-r--r--intern/cycles/device/opencl/opencl_util.cpp2
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp20
-rw-r--r--intern/cycles/util/util_types_float4.h1
-rw-r--r--intern/cycles/util/util_types_float4_impl.h5
-rw-r--r--intern/openvdb/CMakeLists.txt7
-rw-r--r--intern/openvdb/intern/openvdb_writer.cc2
-rw-r--r--intern/rigidbody/RBI_api.h1
-rw-r--r--intern/rigidbody/rb_bullet_api.cpp28
-rw-r--r--release/scripts/startup/bl_operators/bmesh/find_adjacent.py15
-rw-r--r--release/scripts/startup/bl_operators/file.py54
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py34
-rw-r--r--release/scripts/startup/bl_ui/space_info.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py32
-rw-r--r--source/blender/blenkernel/BKE_armature.h20
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h17
-rw-r--r--source/blender/blenkernel/BKE_image.h5
-rw-r--r--source/blender/blenkernel/BKE_main.h6
-rw-r--r--source/blender/blenkernel/BKE_modifier.h1
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h6
-rw-r--r--source/blender/blenkernel/BKE_text.h48
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h196
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/armature.c1
-rw-r--r--source/blender/blenkernel/intern/armature_update.c63
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c303
-rw-r--r--source/blender/blenkernel/intern/cachefile.c1
-rw-r--r--source/blender/blenkernel/intern/camera.c1
-rw-r--r--source/blender/blenkernel/intern/displist.c5
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c1
-rw-r--r--source/blender/blenkernel/intern/image.c198
-rw-r--r--source/blender/blenkernel/intern/lamp.c1
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/library.c3
-rw-r--r--source/blender/blenkernel/intern/linestyle.c1
-rw-r--r--source/blender/blenkernel/intern/mask.c1
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c1
-rw-r--r--source/blender/blenkernel/intern/mesh.c2
-rw-r--r--source/blender/blenkernel/intern/modifier.c24
-rw-r--r--source/blender/blenkernel/intern/object.c9
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c4
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c70
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c1
-rw-r--r--source/blender/blenkernel/intern/sequencer.c7
-rw-r--r--source/blender/blenkernel/intern/smoke.c1
-rw-r--r--source/blender/blenkernel/intern/speaker.c1
-rw-r--r--source/blender/blenkernel/intern/text.c519
-rw-r--r--source/blender/blenkernel/intern/texture.c1
-rw-r--r--source/blender/blenkernel/intern/undo_system.c831
-rw-r--r--source/blender/blenkernel/intern/world.c1
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c59
-rw-r--r--source/blender/blenlib/BLI_listbase.h2
-rw-r--r--source/blender/blenlib/BLI_sort_utils.h7
-rw-r--r--source/blender/blenlib/BLI_string.h14
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h10
-rw-r--r--source/blender/blenlib/BLI_utildefines.h2
-rw-r--r--source/blender/blenlib/intern/listbase.c2
-rw-r--r--source/blender/blenlib/intern/sort_utils.c22
-rw-r--r--source/blender/blenloader/BLO_readfile.h2
-rw-r--r--source/blender/blenloader/BLO_undofile.h14
-rw-r--r--source/blender/blenloader/intern/readfile.c31
-rw-r--r--source/blender/blenloader/intern/undofile.c78
-rw-r--r--source/blender/blenloader/intern/versioning_270.c17
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h20
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h4
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c2
-rw-r--r--source/blender/collada/AnimationImporter.cpp48
-rw-r--r--source/blender/collada/AnimationImporter.h3
-rw-r--r--source/blender/collada/DocumentImporter.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc86
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h16
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc76
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc74
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc80
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc6
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c2
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c2
-rw-r--r--source/blender/editors/armature/editarmature_undo.c119
-rw-r--r--source/blender/editors/armature/pose_edit.c53
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/curve/editcurve.c3
-rw-r--r--source/blender/editors/curve/editcurve_add.c2
-rw-r--r--source/blender/editors/curve/editcurve_undo.c169
-rw-r--r--source/blender/editors/curve/editfont_undo.c122
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c1
-rw-r--r--source/blender/editors/include/ED_armature.h14
-rw-r--r--source/blender/editors/include/ED_curve.h8
-rw-r--r--source/blender/editors/include/ED_lattice.h4
-rw-r--r--source/blender/editors/include/ED_mball.h4
-rw-r--r--source/blender/editors/include/ED_mesh.h6
-rw-r--r--source/blender/editors/include/ED_object.h12
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h11
-rw-r--r--source/blender/editors/include/ED_sculpt.h6
-rw-r--r--source/blender/editors/include/ED_text.h10
-rw-r--r--source/blender/editors/include/ED_undo.h64
-rw-r--r--source/blender/editors/include/ED_util.h39
-rw-r--r--source/blender/editors/interface/interface_handlers.c2
-rw-r--r--source/blender/editors/interface/interface_ops.c3
-rw-r--r--source/blender/editors/interface/interface_region_popup.c17
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/io/io_cache.c1
-rw-r--r--source/blender/editors/io/io_collada.c5
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c120
-rw-r--r--source/blender/editors/lattice/lattice_intern.h2
-rw-r--r--source/blender/editors/lattice/lattice_ops.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c4
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c196
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-rw-r--r--source/blender/editors/metaball/editmball_undo.c116
-rw-r--r--source/blender/editors/object/object_add.c10
-rw-r--r--source/blender/editors/object/object_edit.c20
-rw-r--r--source/blender/editors/object/object_modes.c40
-rw-r--r--source/blender/editors/physics/particle_edit.c5
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c255
-rw-r--r--source/blender/editors/physics/particle_object.c8
-rw-r--r--source/blender/editors/physics/physics_fluid.c4
-rw-r--r--source/blender/editors/physics/physics_intern.h1
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c1
-rw-r--r--source/blender/editors/physics/rigidbody_object.c1
-rw-r--r--source/blender/editors/render/render_internal.c8
-rw-r--r--source/blender/editors/screen/area.c27
-rw-r--r--source/blender/editors/screen/screen_ops.c1
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c161
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c14
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c226
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h10
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c410
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c170
-rw-r--r--source/blender/editors/space_action/action_buttons.c2
-rw-r--r--source/blender/editors/space_action/action_data.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c2
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c1
-rw-r--r--source/blender/editors/space_file/file_draw.c2
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c7
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_edit.c2
-rw-r--r--source/blender/editors/space_node/node_templates.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c19
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c6
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c13
-rw-r--r--source/blender/editors/space_text/text_ops.c143
-rw-r--r--source/blender/editors/space_text/text_undo.c185
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c2
-rw-r--r--source/blender/editors/transform/transform.c14
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c10
-rw-r--r--source/blender/editors/undo/CMakeLists.txt45
-rw-r--r--source/blender/editors/undo/ed_undo.c (renamed from source/blender/editors/util/undo.c)416
-rw-r--r--source/blender/editors/undo/memfile_undo.c149
-rw-r--r--source/blender/editors/undo/undo_intern.h (renamed from source/blender/editors/util/util_intern.h)27
-rw-r--r--source/blender/editors/undo/undo_system_types.c74
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/ed_util.c17
-rw-r--r--source/blender/editors/util/editmode_undo.c372
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h22
-rw-r--r--source/blender/imbuf/IMB_metadata.h (renamed from source/blender/imbuf/intern/IMB_metadata.h)42
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c2
-rw-r--r--source/blender/imbuf/intern/anim_movie.c26
-rw-r--r--source/blender/imbuf/intern/colormanagement.c1
-rw-r--r--source/blender/imbuf/intern/jpeg.c6
-rw-r--r--source/blender/imbuf/intern/metadata.c90
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp3
-rw-r--r--source/blender/imbuf/intern/png.c3
-rw-r--r--source/blender/imbuf/intern/scaling.c40
-rw-r--r--source/blender/imbuf/intern/thumbs.c19
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c1
-rw-r--r--source/blender/imbuf/intern/util.c3
-rw-r--r--source/blender/imbuf/intern/writeimage.c19
-rw-r--r--source/blender/makesdna/DNA_action_types.h7
-rw-r--r--source/blender/makesdna/DNA_scene_types.h34
-rw-r--r--source/blender/makesdna/DNA_text_types.h4
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_ID.c23
-rw-r--r--source/blender/makesrna/intern/rna_access.c4
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c28
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c2
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c24
-rw-r--r--source/blender/makesrna/intern/rna_rna.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c70
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c36
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c2
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c4
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c10
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c6
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c10
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c10
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.c2
-rw-r--r--source/blender/physics/intern/implicit_blender.c1
-rw-r--r--source/blender/python/BPY_extern_clog.h35
-rw-r--r--source/blender/python/generic/py_capi_utils.c58
-rw-r--r--source/blender/python/generic/py_capi_utils.h4
-rw-r--r--source/blender/python/intern/CMakeLists.txt8
-rw-r--r--source/blender/python/intern/bpy_interface.c18
-rw-r--r--source/blender/python/intern/bpy_rna.c33
-rw-r--r--source/blender/python/intern/bpy_rna_array.c7
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c7
-rw-r--r--source/blender/render/intern/source/render_result.c2
-rw-r--r--source/blender/windowmanager/intern/wm.c8
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c1
-rw-r--r--source/blender/windowmanager/intern/wm_files.c22
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c20
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
-rw-r--r--source/blender/windowmanager/intern/wm_window.c2
-rw-r--r--source/creator/creator_args.c7
-rw-r--r--source/creator/creator_signals.c40
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp2
257 files changed, 5168 insertions, 3200 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 212587d6d08..f0930866d64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -251,6 +251,8 @@ option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" _init_OPEN
option(WITH_OPENVDB "Enable features relying on OpenVDB" OFF)
option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" OFF)
+option(WITH_OPENVDB_3_ABI_COMPATIBLE "Assume OpenVDB library has been compiled with version 3 ABI compatibility" OFF)
+mark_as_advanced(WITH_OPENVDB_3_ABI_COMPATIBLE)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
@@ -1496,8 +1498,8 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_SIGN_COMPARE -Wno-sign-compare)
# disable numbered, false positives
- set(C_WARNINGS "${C_WARNINGS} -wd188,186,144,913,556")
- set(CXX_WARNINGS "${CXX_WARNINGS} -wd188,186,144,913,556")
+ set(C_WARNINGS "${C_WARNINGS} -wd188,186,144,913,556,858,597,177,1292,167,279,592,94,2722,3199")
+ set(CXX_WARNINGS "${CXX_WARNINGS} -wd188,186,144,913,556,858,597,177,1292,167,279,592,94,2722,3199")
elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
# most msvc warnings are C & C++
set(_WARNINGS
diff --git a/build_files/build_environment/cmake/openal.cmake b/build_files/build_environment/cmake/openal.cmake
index d63c4443ca0..3331361bfbc 100644
--- a/build_files/build_environment/cmake/openal.cmake
+++ b/build_files/build_environment/cmake/openal.cmake
@@ -25,6 +25,7 @@ if(BUILD_MODE STREQUAL Release)
-DALSOFT_CONFIG=Off
-DALSOFT_HRTF_DEFS=Off
-DALSOFT_INSTALL=On
+ -DALSOFT_BACKEND_SNDIO=Off
)
if(UNIX)
diff --git a/build_files/build_environment/cmake/openimageio.cmake b/build_files/build_environment/cmake/openimageio.cmake
index 07f6b3cdbef..fdc71508e47 100644
--- a/build_files/build_environment/cmake/openimageio.cmake
+++ b/build_files/build_environment/cmake/openimageio.cmake
@@ -90,6 +90,7 @@ set(OPENIMAGEIO_EXTRA_ARGS
-DUSE_PYTHON=OFF
-DUSE_PYTHON3=OFF
-DUSE_OCIO=OFF
+ -DUSE_WEBP=${WITH_WEBP}
-DOIIO_BUILD_TOOLS=${OIIO_TOOLS}
-DOIIO_BUILD_TESTS=OFF
-DBUILD_TESTING=OFF
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index f0cff75c417..107b29e0cc8 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -559,6 +559,8 @@ function(SETUP_BLENDER_SORTED_LIBS)
set(BLENDER_SORTED_LIBS
bf_windowmanager
+ bf_editor_undo
+
bf_editor_space_api
bf_editor_space_action
bf_editor_space_buttons
@@ -805,7 +807,7 @@ macro(TEST_SSE_SUPPORT
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
set(${_sse_flags} "") # icc defaults to -msse
- set(${_sse2_flags} "-msse2")
+ set(${_sse2_flags} "") # icc defaults to -msse2
else()
message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
set(${_sse_flags})
diff --git a/doc/doxygen/doxygen.source.h b/doc/doxygen/doxygen.source.h
index 16ebe407f5f..9390193ae20 100644
--- a/doc/doxygen/doxygen.source.h
+++ b/doc/doxygen/doxygen.source.h
@@ -316,6 +316,10 @@
* \ingroup editors
*/
+/** \defgroup edundo undo utilities
+ * \ingroup editors
+ */
+
/** \defgroup spuv UV editing
* \ingroup editors
*/
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
index 49ff78c2621..31371944864 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
@@ -782,6 +782,12 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
btScalar cfm = BT_ZERO;
btScalar mA = BT_ONE / m_rbA.getInvMass();
btScalar mB = BT_ONE / m_rbB.getInvMass();
+ if (rotational) {
+ btScalar rrA = (m_calculatedTransformA.getOrigin() - transA.getOrigin()).length2();
+ btScalar rrB = (m_calculatedTransformB.getOrigin() - transB.getOrigin()).length2();
+ if (m_rbA.getInvMass()) mA = mA * rrA + 1 / (m_rbA.getInvInertiaTensorWorld() * ax1).length();
+ if (m_rbB.getInvMass()) mB = mB * rrB + 1 / (m_rbB.getInvInertiaTensorWorld() * ax1).length();
+ }
btScalar m = mA > mB ? mB : mA;
btScalar angularfreq = sqrt(ks / m);
@@ -800,7 +806,18 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt;
btScalar f = (fs+fd);
- info->m_constraintError[srow] = (vel + f * (rotational ? -1 : 1)) ;
+ // after the spring force affecting the body(es) the new velocity will be
+ // vel + f / m * (rotational ? -1 : 1)
+ // so in theory this should be set here for m_constraintError
+ // (with m_constraintError we set a desired velocity for the affected body(es))
+ // however in practice any value is fine as long as it is greater then the "proper" velocity,
+ // because the m_lowerLimit and the m_upperLimit will determinate the strength of the final pulling force
+ // so it is much simpler (and more robust) just to simply use inf (with the proper sign)
+ // you may also wonder what if the current velocity (vel) so high that the pulling force will not change its direction (in this iteration)
+ // will we not request a velocity with the wrong direction ?
+ // and the answare is not, because in practice during the solving the current velocity is subtracted from the m_constraintError
+ // so the sign of the force that is really matters
+ info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY);
btScalar minf = f < fd ? f : fd;
btScalar maxf = f < fd ? fd : f;
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
index 291d5712973..dfbd34d341a 100644
--- a/intern/clog/clog.c
+++ b/intern/clog/clog.c
@@ -236,8 +236,7 @@ static const char *clg_severity_as_text(enum CLG_Severity severity)
static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
{
- bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
- assert(ok);
+ assert((unsigned int)severity < CLG_SEVERITY_LEN);
enum eCLogColor color = COLOR_DEFAULT;
switch (severity) {
case CLG_SEVERITY_INFO:
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 9df1e91e239..c3305ac3dd8 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -104,6 +104,54 @@ elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CYCLES_KERNEL_FLAGS}")
+elseif(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ check_cxx_compiler_flag(/QxSSE2 CXX_HAS_SSE)
+ check_cxx_compiler_flag(/arch:AVX CXX_HAS_AVX)
+ check_cxx_compiler_flag(/QxCORE-AVX2 CXX_HAS_AVX2)
+
+ if(CXX_HAS_SSE)
+ set(CYCLES_SSE2_KERNEL_FLAGS "/QxSSE2")
+ set(CYCLES_SSE3_KERNEL_FLAGS "/QxSSSE3")
+ set(CYCLES_SSE41_KERNEL_FLAGS "/QxSSE4.1")
+
+ if(CXX_HAS_AVX)
+ set(CYCLES_AVX_KERNEL_FLAGS "/arch:AVX")
+ endif()
+
+ if(CXX_HAS_AVX2)
+ set(CYCLES_AVX2_KERNEL_FLAGS "/QxCORE-AVX2")
+ endif()
+ endif()
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ if(APPLE)
+ # ICC does not support SSE2 flag on MacOSX
+ check_cxx_compiler_flag(-xssse3 CXX_HAS_SSE)
+ else()
+ check_cxx_compiler_flag(-xsse2 CXX_HAS_SSE)
+ endif()
+
+ check_cxx_compiler_flag(-xavx CXX_HAS_AVX)
+ check_cxx_compiler_flag(-xcore-avx2 CXX_HAS_AVX2)
+
+ if(CXX_HAS_SSE)
+ if(APPLE)
+ # ICC does not support SSE2 flag on MacOSX
+ set(CYCLES_SSE2_KERNEL_FLAGS "-xssse3")
+ else()
+ set(CYCLES_SSE2_KERNEL_FLAGS "-xsse2")
+ endif()
+
+ set(CYCLES_SSE3_KERNEL_FLAGS "-xssse3")
+ set(CYCLES_SSE41_KERNEL_FLAGS "-xsse4.1")
+
+ if(CXX_HAS_AVX)
+ set(CYCLES_AVX_KERNEL_FLAGS "-xavx")
+ endif()
+
+ if(CXX_HAS_AVX2)
+ set(CYCLES_AVX2_KERNEL_FLAGS "-xcore-avx2")
+ endif()
+ endif()
endif()
if(CXX_HAS_SSE)
diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp
index a776f48b5e9..78ed401bff5 100644
--- a/intern/cycles/device/opencl/opencl_util.cpp
+++ b/intern/cycles/device/opencl/opencl_util.cpp
@@ -633,7 +633,7 @@ bool OpenCLInfo::device_supported(const string& platform_name,
}
const char *blacklist[] = {
/* GCN 1 */
- "Tahiti", "Pitcairn", "Capeverde", "Oland",
+ "Tahiti", "Pitcairn", "Capeverde", "Oland", "Hainan",
NULL
};
for(int i = 0; blacklist[i] != NULL; i++) {
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
index 585ed77b026..9dd81eb6700 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -204,7 +204,9 @@ public:
src = dest;
}
- patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
+ if(num_local_points) {
+ patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
+ }
/* create patch map */
patch_map = new Far::PatchMap(*patch_table);
@@ -236,13 +238,15 @@ public:
src = dest;
}
- if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
- patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0],
- (OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
- }
- else {
- patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0],
- (OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ if(num_local_points) {
+ if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
+ patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0],
+ (OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ else {
+ patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0],
+ (OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
}
}
else if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
diff --git a/intern/cycles/util/util_types_float4.h b/intern/cycles/util/util_types_float4.h
index a7d9abe1b95..154391f6881 100644
--- a/intern/cycles/util/util_types_float4.h
+++ b/intern/cycles/util/util_types_float4.h
@@ -34,7 +34,6 @@ struct ccl_try_align(16) float4 {
};
__forceinline float4();
- __forceinline float4(const float4& a);
__forceinline explicit float4(const __m128& a);
__forceinline operator const __m128&(void) const;
diff --git a/intern/cycles/util/util_types_float4_impl.h b/intern/cycles/util/util_types_float4_impl.h
index ff3ec4d4ecf..09f45f47d38 100644
--- a/intern/cycles/util/util_types_float4_impl.h
+++ b/intern/cycles/util/util_types_float4_impl.h
@@ -33,11 +33,6 @@ __forceinline float4::float4()
{
}
-__forceinline float4::float4(const float4& a)
- : m128(a.m128)
-{
-}
-
__forceinline float4::float4(const __m128& a)
: m128(a)
{
diff --git a/intern/openvdb/CMakeLists.txt b/intern/openvdb/CMakeLists.txt
index 4b872f25d45..f666dc78e75 100644
--- a/intern/openvdb/CMakeLists.txt
+++ b/intern/openvdb/CMakeLists.txt
@@ -38,9 +38,14 @@ set(SRC
if(WITH_OPENVDB)
add_definitions(
-DWITH_OPENVDB
- -DOPENVDB_3_ABI_COMPATIBLE
)
+ if(WITH_OPENVDB_3_ABI_COMPATIBLE)
+ add_definitions(
+ -DOPENVDB_3_ABI_COMPATIBLE
+ )
+ endif()
+
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
${TBB_INCLUDE_DIRS}
diff --git a/intern/openvdb/intern/openvdb_writer.cc b/intern/openvdb/intern/openvdb_writer.cc
index b83691ac7de..bedcfe65552 100644
--- a/intern/openvdb/intern/openvdb_writer.cc
+++ b/intern/openvdb/intern/openvdb_writer.cc
@@ -45,7 +45,7 @@ void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
void OpenVDBWriter::insert(const openvdb::GridBase &grid)
{
-#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER >= 3)
+#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER <= 3) || defined(OPENVDB_3_ABI_COMPATIBLE)
m_grids->push_back(grid.copyGrid());
#else
m_grids->push_back(grid.copyGridWithNewTree());
diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h
index 688ca91c774..556ca959e64 100644
--- a/intern/rigidbody/RBI_api.h
+++ b/intern/rigidbody/RBI_api.h
@@ -299,6 +299,7 @@ void RB_constraint_set_limits_piston(rbConstraint *con, float lin_lower, float l
void RB_constraint_set_limits_6dof(rbConstraint *con, int axis, float lower, float upper);
/* 6dof spring specific */
+void RB_constraint_set_limits_6dof_spring(rbConstraint *con, int axis, float lower, float upper);
void RB_constraint_set_stiffness_6dof_spring(rbConstraint *con, int axis, float stiffness);
void RB_constraint_set_damping_6dof_spring(rbConstraint *con, int axis, float damping);
void RB_constraint_set_spring_6dof_spring(rbConstraint *con, int axis, int enable);
diff --git a/intern/rigidbody/rb_bullet_api.cpp b/intern/rigidbody/rb_bullet_api.cpp
index 17bb3817908..a9fbcb28529 100644
--- a/intern/rigidbody/rb_bullet_api.cpp
+++ b/intern/rigidbody/rb_bullet_api.cpp
@@ -954,7 +954,7 @@ rbConstraint *RB_constraint_new_6dof_spring(float pivot[3], float orn[4], rbRigi
make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn);
- btTypedConstraint *con = new btGeneric6DofSpringConstraint(*body1, *body2, transform1, transform2, true);
+ btTypedConstraint *con = new btGeneric6DofSpring2Constraint(*body1, *body2, transform1, transform2);
return (rbConstraint *)con;
}
@@ -1034,32 +1034,38 @@ void RB_constraint_set_limits_6dof(rbConstraint *con, int axis, float lower, flo
constraint->setLimit(axis, lower, upper);
}
+void RB_constraint_set_limits_6dof_spring(rbConstraint *con, int axis, float lower, float upper)
+{
+ btGeneric6DofSpring2Constraint *constraint = reinterpret_cast<btGeneric6DofSpring2Constraint*>(con);
+
+ constraint->setLimit(axis, lower, upper);
+}
+
void RB_constraint_set_stiffness_6dof_spring(rbConstraint *con, int axis, float stiffness)
{
- btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con);
-
+ btGeneric6DofSpring2Constraint *constraint = reinterpret_cast<btGeneric6DofSpring2Constraint*>(con);
+
constraint->setStiffness(axis, stiffness);
}
void RB_constraint_set_damping_6dof_spring(rbConstraint *con, int axis, float damping)
{
- btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con);
-
- // invert damping range so that 0 = no damping
- constraint->setDamping(axis, 1.0f - damping);
+ btGeneric6DofSpring2Constraint *constraint = reinterpret_cast<btGeneric6DofSpring2Constraint*>(con);
+
+ constraint->setDamping(axis, damping);
}
void RB_constraint_set_spring_6dof_spring(rbConstraint *con, int axis, int enable)
{
- btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con);
-
+ btGeneric6DofSpring2Constraint *constraint = reinterpret_cast<btGeneric6DofSpring2Constraint*>(con);
+
constraint->enableSpring(axis, enable);
}
void RB_constraint_set_equilibrium_6dof_spring(rbConstraint *con)
{
- btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con);
-
+ btGeneric6DofSpring2Constraint *constraint = reinterpret_cast<btGeneric6DofSpring2Constraint*>(con);
+
constraint->setEquilibriumPoint();
}
diff --git a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
index 77e590fd8ce..ff2e09c6bb5 100644
--- a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
+++ b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
@@ -113,7 +113,7 @@ def elems_depth_search(ele_init, depths, other_edges_over_cb, results_init=None)
else:
test_ele = {
v for v, depth in vert_depths.items()
- if depth >= depth_min for e in v.link_edges if not e.is_wire}
+ if depth >= depth_min}
result_ele = set()
@@ -203,6 +203,7 @@ def find_next(ele_dst, ele_src):
candidates = elems_depth_search(ele_dst, depth_src_a, other_edges_over_edge)
candidates = elems_depth_search(ele_dst, depth_src_b, other_edges_over_face, candidates)
candidates.discard(ele_src)
+ candidates.discard(ele_dst)
if not candidates:
return []
@@ -212,11 +213,12 @@ def find_next(ele_dst, ele_src):
# ... So we have the highest chance of stepping onto the opposite element.
diff_best = 0
ele_best = None
- ele_best_tot = 0
ele_best_ls = []
for ele_test in candidates:
depth_test_a = elems_depth_measure(ele_dst, ele_test, other_edges_over_edge)
depth_test_b = elems_depth_measure(ele_dst, ele_test, other_edges_over_face)
+ if depth_test_a is None or depth_test_b is None:
+ continue
depth_test = tuple(zip(depth_test_a, depth_test_b))
# square so a few high values win over many small ones
diff_test = sum((abs(a[0] - b[0]) ** 2) +
@@ -224,12 +226,10 @@ def find_next(ele_dst, ele_src):
if diff_test > diff_best:
diff_best = diff_test
ele_best = ele_test
- ele_best_tot = 1
ele_best_ls[:] = [ele_best]
elif diff_test == diff_best:
if ele_best is None:
ele_best = ele_test
- ele_best_tot += 1
ele_best_ls.append(ele_test)
if len(ele_best_ls) > 1:
@@ -237,9 +237,12 @@ def find_next(ele_dst, ele_src):
ele_best_ls = []
depth_accum_max = -1
for ele_test in ele_best_ls_init:
+ depth_test_a = elems_depth_measure(ele_src, ele_test, other_edges_over_edge)
+ depth_test_b = elems_depth_measure(ele_src, ele_test, other_edges_over_face)
+ if depth_test_a is None or depth_test_b is None:
+ continue
depth_accum_test = (
- sum(elems_depth_measure(ele_src, ele_test, other_edges_over_edge)) +
- sum(elems_depth_measure(ele_src, ele_test, other_edges_over_face)))
+ sum(depth_test_a) + sum(depth_test_b))
if depth_accum_test > depth_accum_max:
depth_accum_max = depth_accum_test
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index 1b51906a032..4ab8d59f263 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -249,7 +249,61 @@ class WM_OT_previews_batch_clear(Operator):
return {'FINISHED'}
+class WM_OT_blend_strings_utf8_validate(Operator):
+ """Check and fix all strings in current .blend file to be valid UTF-8 Unicode (needed for some old, 2.4x area files)"""
+ bl_idname = "wm.blend_strings_utf8_validate"
+ bl_label = "Validate .blend strings"
+ bl_options = {'REGISTER'}
+
+ def validate_strings(self, item, done_items):
+ if item is None:
+ return False
+
+ if item in done_items:
+ return False
+ done_items.add(item)
+
+ if getattr(item, 'library', None) is not None:
+ return False # No point in checking library data, we cannot fix it anyway...
+
+ changed = False
+ for prop in item.bl_rna.properties:
+ if prop.identifier in {'bl_rna', 'rna_type'}:
+ continue # Or we'd recurse 'till Hell freezes.
+ if prop.is_readonly:
+ continue
+ if prop.type == 'STRING':
+ val_bytes = item.path_resolve(prop.identifier, False).as_bytes()
+ val_utf8 = val_bytes.decode('utf-8', 'replace')
+ val_bytes_valid = val_utf8.encode('utf-8')
+ if val_bytes_valid != val_bytes:
+ print("found bad utf8 encoded string %r, fixing to %r (%r)..."
+ "" % (val_bytes, val_bytes_valid, val_utf8))
+ setattr(item, prop.identifier, val_utf8)
+ changed = True
+ elif prop.type == 'POINTER':
+ it = getattr(item, prop.identifier)
+ changed |= self.validate_strings(it, done_items)
+ elif prop.type == 'COLLECTION':
+ for it in getattr(item, prop.identifier):
+ changed |= self.validate_strings(it, done_items)
+ return changed
+
+ def execute(self, context):
+ changed = False
+ done_items = set()
+ for prop in bpy.data.bl_rna.properties:
+ if prop.type == 'COLLECTION':
+ for it in getattr(bpy.data, prop.identifier):
+ changed |= self.validate_strings(it, done_items)
+ if changed:
+ self.report({'WARNING'},
+ "Some strings were fixed, don't forget to save the .blend file to keep those changes")
+ return {'FINISHED'}
+
+
classes = (
WM_OT_previews_batch_clear,
WM_OT_previews_batch_generate,
+ WM_OT_blend_strings_utf8_validate,
)
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 41ebf8196d2..a5ce345a93c 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -369,6 +369,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
col.prop(rd, "use_stamp_camera", text="Camera")
col.prop(rd, "use_stamp_lens", text="Lens")
col.prop(rd, "use_stamp_filename", text="Filename")
+ col.prop(rd, "use_stamp_frame_range", text="Frame range")
col.prop(rd, "use_stamp_marker", text="Marker")
col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip")
@@ -433,17 +434,37 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
split.prop(rd.ffmpeg, "format")
split.prop(ffmpeg, "use_autosplit")
+ # Video:
layout.separator()
+ self.draw_vcodec(context)
+
+ # Audio:
+ layout.separator()
+ if ffmpeg.format != 'MP3':
+ layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
+
+ if ffmpeg.audio_codec != 'NONE':
+ row = layout.row()
+ row.prop(ffmpeg, "audio_bitrate")
+ row.prop(ffmpeg, "audio_volume", slider=True)
+
+ def draw_vcodec(self, context):
+ """Video codec options."""
+ layout = self.layout
+ ffmpeg = context.scene.render.ffmpeg
needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4'}
if needs_codec:
layout.prop(ffmpeg, "codec")
+ if needs_codec and ffmpeg.codec == 'NONE':
+ return
+
if ffmpeg.codec in {'DNXHD'}:
layout.prop(ffmpeg, "use_lossless_output")
# Output quality
- use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4'}
+ use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4', 'WEBM'}
if use_crf:
layout.prop(ffmpeg, "constant_rate_factor")
@@ -472,17 +493,6 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
col.prop(ffmpeg, "muxrate", text="Rate")
col.prop(ffmpeg, "packetsize", text="Packet Size")
- layout.separator()
-
- # Audio:
- if ffmpeg.format != 'MP3':
- layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
-
- if ffmpeg.audio_codec != 'NONE':
- row = layout.row()
- row.prop(ffmpeg, "audio_bitrate")
- row.prop(ffmpeg, "audio_volume", slider=True)
-
class RENDER_PT_bake(RenderButtonsPanel, Panel):
bl_label = "Bake"
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index a7b518dfd2e..180e48af386 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -154,6 +154,7 @@ class INFO_MT_file(Menu):
layout.separator()
layout.menu("INFO_MT_file_external_data", icon='EXTERNAL_DATA')
+ layout.operator("wm.blend_strings_utf8_validate", icon='FILE_BLEND')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index fbda0df18a6..a618ef7fd4e 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2668,8 +2668,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("object.vertex_parent_set")
-class VIEW3D_MT_edit_mesh_edges(Menu):
- bl_label = "Edges"
+class VIEW3D_MT_edit_mesh_edges_data(Menu):
+ bl_label = "Edge Data"
def draw(self, context):
layout = self.layout
@@ -2678,13 +2678,6 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("mesh.edge_face_add")
- layout.operator("mesh.subdivide")
- layout.operator("mesh.subdivide_edgering")
- layout.operator("mesh.unsubdivide")
-
- layout.separator()
-
layout.operator("transform.edge_crease")
layout.operator("transform.edge_bevelweight")
@@ -2705,6 +2698,26 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
layout.separator()
+
+class VIEW3D_MT_edit_mesh_edges(Menu):
+ bl_label = "Edges"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ layout.operator("mesh.edge_face_add")
+ layout.operator("mesh.subdivide")
+ layout.operator("mesh.subdivide_edgering")
+ layout.operator("mesh.unsubdivide")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_mesh_edges_data")
+
+ layout.separator()
+
layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
layout.operator("mesh.edge_rotate", text="Rotate Edge CCW").use_ccw = True
@@ -4111,6 +4124,7 @@ classes = (
VIEW3D_MT_edit_mesh_extrude,
VIEW3D_MT_edit_mesh_vertices,
VIEW3D_MT_edit_mesh_edges,
+ VIEW3D_MT_edit_mesh_edges_data,
VIEW3D_MT_edit_mesh_faces,
VIEW3D_MT_edit_mesh_normals,
VIEW3D_MT_edit_mesh_clean,
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 60fb79d75d5..f6de39c897e 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -169,41 +169,39 @@ void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bP
void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
struct Scene *scene,
- struct Object *ob,
- struct bPose *pose);
+ struct Object *ob);
void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx,
struct Scene *scene,
- struct Object *ob,
- struct bPose *pose);
+ struct Object *ob);
void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
- struct bPoseChannel *pchan);
+ int pchan_index);
void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
- struct bPoseChannel *pchan);
+ int pchan_index);
void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
- struct bPoseChannel *pchan);
+ struct Object *ob,
+ int pchan_index);
void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
- struct bPoseChannel *rootchan);
+ int rootchan_index);
void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
- struct bPoseChannel *rootchan);
+ int rootchan_index);
void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
struct Scene *scene,
- struct Object *ob,
- struct bPose *pose);
+ struct Object *ob);
void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 84a6d07be7d..a96f8af1fdb 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -31,22 +31,13 @@ extern "C" {
struct bContext;
struct Scene;
struct Main;
+struct MemFileUndoData;
#define BKE_UNDO_STR_MAX 64
-/* global undo */
-extern void BKE_undo_write(struct bContext *C, const char *name);
-extern void BKE_undo_step(struct bContext *C, int step);
-extern void BKE_undo_name(struct bContext *C, const char *name);
-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);
-
-extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C));
+struct MemFileUndoData *BKE_memfile_undo_encode(struct Main *bmain, struct MemFileUndoData *mfu_prev);
+bool BKE_memfile_undo_decode(struct MemFileUndoData *mfu, struct bContext *C);
+void BKE_memfile_undo_free(struct MemFileUndoData *mfu);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 57459412efc..1af123759e6 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -67,6 +67,11 @@ void BKE_image_init(struct Image *image);
typedef void (StampCallback)(void *data, const char *propname, char *propvalue, int len);
void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr, bool allocate_only);
+/**
+ * Fills in the static stamp data (i.e. everything except things that can change per frame).
+ * The caller is responsible for freeing the allocated memory.
+ */
+struct StampData *BKE_stamp_info_from_scene_static(struct Scene *scene);
void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index d8318bfcf5d..e224155726f 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -84,10 +84,12 @@ typedef struct Main {
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
- short recovered; /* indicate the main->name (file) is the recovered one */
+ char recovered; /* indicate the main->name (file) is the recovered one */
+ /** All current ID's exist in the last memfile undo step. */
+ char is_memfile_undo_written;
BlendThumbnail *blen_thumb;
-
+
struct Library *curlib;
ListBase scene;
ListBase library;
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index b0917e4f6cd..18cde156f5e 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -346,6 +346,7 @@ const ModifierTypeInfo *modifierType_getInfo(ModifierType type);
* default values if pointer is optional.
*/
struct ModifierData *modifier_new(int type);
+void modifier_free_ex(struct ModifierData *md, const int flag);
void modifier_free(struct ModifierData *md);
bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 5578290c41a..3fea26e7359 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -73,7 +73,7 @@ void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *
bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type);
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
-void BKE_object_free_modifiers(struct Object *ob);
+void BKE_object_free_modifiers(struct Object *ob, const int flag);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index f31ae715539..cc60df1b2d6 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -227,7 +227,6 @@ typedef struct PTCacheEditPoint {
} PTCacheEditPoint;
typedef struct PTCacheUndo {
- struct PTCacheUndo *next, *prev;
struct PTCacheEditPoint *points;
/* particles stuff */
@@ -240,12 +239,11 @@ typedef struct PTCacheUndo {
struct ListBase mem_cache;
int totpoint;
- char name[64];
+
+ size_t undo_size;
} PTCacheUndo;
typedef struct PTCacheEdit {
- ListBase undo;
- struct PTCacheUndo *curundo;
PTCacheEditPoint *points;
struct PTCacheID pid;
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b3b1ad23b32..98db06752c8 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -40,6 +40,7 @@ extern "C" {
struct Main;
struct Text;
struct TextLine;
+struct TextUndoBuf;
void BKE_text_free_lines (struct Text *text);
void BKE_text_free (struct Text *text);
@@ -55,8 +56,8 @@ struct Text *BKE_text_load (struct Main *bmain, const char *file, const char
void BKE_text_copy_data(struct Main *bmain, struct Text *ta_dst, const struct Text *ta_src, const int flag);
struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta);
void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local);
-void BKE_text_clear (struct Text *text);
-void BKE_text_write (struct Text *text, const char *str);
+void BKE_text_clear (struct Text *text, struct TextUndoBuf *utxt);
+void BKE_text_write (struct Text *text, struct TextUndoBuf *utxt, const char *str);
int BKE_text_file_modified_check(struct Text *text);
void BKE_text_file_modified_ignore(struct Text *text);
@@ -83,29 +84,29 @@ void txt_move_eol (struct Text *text, const bool sel);
void txt_move_toline (struct Text *text, unsigned int line, const bool sel);
void txt_move_to (struct Text *text, unsigned int line, unsigned int ch, const bool sel);
void txt_pop_sel (struct Text *text);
-void txt_delete_char (struct Text *text);
-void txt_delete_word (struct Text *text);
-void txt_delete_selected (struct Text *text);
+void txt_delete_char (struct Text *text, struct TextUndoBuf *utxt);
+void txt_delete_word (struct Text *text, struct TextUndoBuf *utxt);
+void txt_delete_selected (struct Text *text, struct TextUndoBuf *utxt);
void txt_sel_all (struct Text *text);
void txt_sel_clear (struct Text *text);
void txt_sel_line (struct Text *text);
char *txt_sel_to_buf (struct Text *text);
-void txt_insert_buf (struct Text *text, const char *in_buffer);
-void txt_undo_add_op (struct Text *text, int op);
-void txt_do_undo (struct Text *text);
-void txt_do_redo (struct Text *text);
-void txt_split_curline (struct Text *text);
-void txt_backspace_char (struct Text *text);
-void txt_backspace_word (struct Text *text);
-bool txt_add_char (struct Text *text, unsigned int add);
-bool txt_add_raw_char (struct Text *text, unsigned int add);
-bool txt_replace_char (struct Text *text, unsigned int add);
-void txt_unindent (struct Text *text);
-void txt_comment (struct Text *text);
-void txt_indent (struct Text *text);
-void txt_uncomment (struct Text *text);
-void txt_move_lines (struct Text *text, const int direction);
-void txt_duplicate_line (struct Text *text);
+void txt_insert_buf (struct Text *text, struct TextUndoBuf *utxt, const char *in_buffer);
+void txt_undo_add_op (struct Text *text, struct TextUndoBuf *utxt, int op);
+void txt_do_undo (struct Text *text, struct TextUndoBuf *utxt);
+void txt_do_redo (struct Text *text, struct TextUndoBuf *utxt);
+void txt_split_curline (struct Text *text, struct TextUndoBuf *utxt);
+void txt_backspace_char (struct Text *text, struct TextUndoBuf *utxt);
+void txt_backspace_word (struct Text *text, struct TextUndoBuf *utxt);
+bool txt_add_char (struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
+bool txt_add_raw_char (struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
+bool txt_replace_char (struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
+void txt_unindent (struct Text *text, struct TextUndoBuf *utxt);
+void txt_comment (struct Text *text, struct TextUndoBuf *utxt);
+void txt_indent (struct Text *text, struct TextUndoBuf *utxt);
+void txt_uncomment (struct Text *text, struct TextUndoBuf *utxt);
+void txt_move_lines (struct Text *text, struct TextUndoBuf *utxt, const int direction);
+void txt_duplicate_line (struct Text *text, struct TextUndoBuf *utxt);
int txt_setcurr_tab_spaces(struct Text *text, int space);
bool txt_cursor_is_line_start(struct Text *text);
bool txt_cursor_is_line_end(struct Text *text);
@@ -135,6 +136,11 @@ enum {
TXT_MOVE_LINE_DOWN = 1
};
+typedef struct TextUndoBuf {
+ char *buf;
+ int pos, len;
+} TextUndoBuf;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
new file mode 100644
index 00000000000..9697c7dd8e2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -0,0 +1,196 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_UNDO_SYSTEM_H__
+#define __BKE_UNDO_SYSTEM_H__
+
+/** \file BKE_undo_system.h
+ * \ingroup bke
+ */
+
+struct Main;
+struct UndoStep;
+struct bContext;
+
+/* ID's */
+struct Mesh;
+struct Object;
+struct Scene;
+struct Text;
+
+#include "DNA_ID.h"
+#include "DNA_listBase.h"
+
+typedef struct UndoRefID { struct ID *ptr; char name[MAX_ID_NAME]; } UndoRefID;
+/* UndoRefID_Mesh & friends. */
+#define UNDO_REF_ID_TYPE(ptr_ty) \
+ typedef struct UndoRefID_##ptr_ty { struct ptr_ty *ptr; char name[MAX_ID_NAME]; } UndoRefID_##ptr_ty
+UNDO_REF_ID_TYPE(Mesh);
+UNDO_REF_ID_TYPE(Object);
+UNDO_REF_ID_TYPE(Scene);
+UNDO_REF_ID_TYPE(Text);
+
+typedef struct UndoStack {
+ ListBase steps;
+ struct UndoStep *step_active;
+
+ /**
+ * Some undo systems require begin/end, see: #UndoType.step_encode_init
+ *
+ * \note This is not included in the 'steps' list.
+ * That is done once end is called.
+ */
+ struct UndoStep *step_init;
+} UndoStack;
+
+
+typedef struct UndoStep {
+ struct UndoStep *next, *prev;
+ char name[64];
+ const struct UndoType *type;
+ /** Size in bytes of all data in step (not including the step). */
+ size_t data_size;
+ /** Users should never see this step (only use for internal consistency). */
+ bool skip;
+ /* Over alloc 'type->struct_size'. */
+} UndoStep;
+
+typedef enum eUndoTypeMode {
+ /**
+ * Each undo step stores a version of the state.
+ * This means we can simply load in a previous state at any time.
+ */
+ BKE_UNDOTYPE_MODE_STORE = 1,
+ /**
+ * Each undo step is a series of edits.
+ * This means to change states we need to apply each edit.
+ * It also means the 'step_decode' callback needs to detect the difference between undo and redo.
+ * (Currently used for text edit and image & sculpt painting).
+ */
+ BKE_UNDOTYPE_MODE_ACCUMULATE = 2,
+} eUndoTypeMode;
+
+typedef void (*UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref);
+
+typedef struct UndoType {
+ struct UndoType *next, *prev;
+ /** Only for debugging. */
+ const char *name;
+
+ /**
+ * When NULL, we don't consider this undo type for context checks.
+ * Operators must explicitly set the undo type and handle adding the undo step.
+ * This is needed when tools operate on data which isn't the primary mode (eg, paint-curve in sculpt mode).
+ */
+ bool (*poll)(struct bContext *C);
+
+ /**
+ * None of these callbacks manage list add/removal.
+ *
+ * Note that 'step_encode_init' is optional,
+ * some undo types need to perform operatons before undo push finishes.
+ */
+ void (*step_encode_init)(struct bContext *C, UndoStep *us);
+
+ bool (*step_encode)(struct bContext *C, UndoStep *us);
+ void (*step_decode)(struct bContext *C, UndoStep *us, int dir);
+
+ /**
+ * \note When freeing all steps,
+ * free from the last since #MemFileUndoType will merge with the next undo type in the list. */
+ void (*step_free)(UndoStep *us);
+
+ void (*step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data);
+
+ eUndoTypeMode mode;
+ bool use_context;
+
+ int step_size;
+} UndoType;
+
+/* expose since we need to perform operations on spesific undo types (rarely). */
+extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE;
+extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE;
+extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE;
+extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE;
+extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT;
+extern const UndoType *BKE_UNDOSYS_TYPE_TEXT;
+
+UndoStack *BKE_undosys_stack_create(void);
+void BKE_undosys_stack_destroy(UndoStack *ustack);
+void BKE_undosys_stack_clear(UndoStack *ustack);
+bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name);
+void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain);
+UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
+UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
+void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
+
+/* Only some UndoType's require init. */
+UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut);
+UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name);
+
+bool BKE_undosys_step_push_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut);
+bool BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name);
+
+UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut);
+UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name);
+
+bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us, bool use_skip);
+bool BKE_undosys_step_undo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us);
+bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C);
+
+bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us, bool use_skip);
+bool BKE_undosys_step_redo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us);
+bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C);
+
+bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep *us);
+
+bool BKE_undosys_step_undo_compat_only(UndoStack *ustack, struct bContext *C, int step);
+void BKE_undosys_step_undo_from_index(UndoStack *ustack, struct bContext *C, int index);
+UndoStep *BKE_undosys_step_same_type_next(UndoStep *us);
+UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us);
+
+/* Type System */
+UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *));
+void BKE_undosys_type_free_all(void);
+
+/* ID Accessor */
+#if 0 /* functionality is only used internally for now. */
+void BKE_undosys_foreach_ID_ref(UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data);
+#endif
+
+/* Use when the undo step stores many arbitrary pointers. */
+struct UndoIDPtrMap;
+struct UndoIDPtrMap *BKE_undosys_ID_map_create(void);
+void BKE_undosys_ID_map_destroy(struct UndoIDPtrMap *map);
+void BKE_undosys_ID_map_add(struct UndoIDPtrMap *map, ID *id);
+struct ID *BKE_undosys_ID_map_lookup(const struct UndoIDPtrMap *map, const struct ID *id_src);
+
+void BKE_undosys_ID_map_add_with_prev(
+ struct UndoIDPtrMap *map, struct ID *id,
+ struct ID **id_prev);
+struct ID *BKE_undosys_ID_map_lookup_with_prev(
+ const struct UndoIDPtrMap *map, struct ID *id_src,
+ struct ID *id_prev_match[2]);
+
+void BKE_undosys_ID_map_foreach_ID_ref(
+ struct UndoIDPtrMap *map,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data);
+
+#endif /* __BKE_UNDO_SYSTEM_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 25954f277b8..d789671ab24 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -188,6 +188,7 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
+ intern/undo_system.c
intern/unit.c
intern/world.c
intern/writeavi.c
@@ -296,6 +297,7 @@ set(SRC
BKE_text.h
BKE_texture.h
BKE_tracking.h
+ BKE_undo_system.h
BKE_unit.h
BKE_world.h
BKE_writeavi.h
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 2edbd088334..70a3772f388 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -64,7 +64,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
-#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index e6bb0d6b7ce..ee63e618b18 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -48,7 +48,6 @@
#include "BIK_api.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "DEG_depsgraph.h"
@@ -552,12 +551,21 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo
/* *************** Depsgraph evaluation callbacks ************ */
+BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
+{
+ bPose *pose = ob->pose;
+ BLI_assert(pose != NULL);
+ BLI_assert(pchan_index >= 0);
+ BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *));
+ return pose->chan_array[pchan_index];
+}
+
void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
Scene *UNUSED(scene),
- Object *ob,
- bPose *pose)
+ Object *ob)
{
- bPoseChannel *pchan;
+ bPose *pose = ob->pose;
+ BLI_assert(pose != NULL);
DEG_debug_print_eval(__func__, ob->id.name, ob);
@@ -570,16 +578,21 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
/* imat is needed for solvers. */
invert_m4_m4(ob->imat, ob->obmat);
- /* 1. clear flags */
- for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ const int num_channels = BLI_listbase_count(&pose->chanbase);
+ pose->chan_array = MEM_malloc_arrayN(
+ num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+
+ /* clear flags */
+ int pchan_index = 0;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ pose->chan_array[pchan_index++] = pchan;
}
}
void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
- Object *ob,
- bPose *UNUSED(pose))
+ Object *ob)
{
DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
@@ -588,11 +601,11 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
if (arm->flag & ARM_RESTPOS) {
return;
}
- /* 2a. construct the IK tree (standard IK) */
+ /* construct the IK tree (standard IK) */
BIK_initialize_tree(scene, ob, ctime);
- /* 2b. construct the Spline IK trees
+ /* construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
- * to function in conjunction with standard IK
+ * to function in conjunction with standard IK
*/
BKE_pose_splineik_init_tree(scene, ob, ctime);
}
@@ -600,8 +613,9 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
- bPoseChannel *pchan)
+ int pchan_index)
{
+ bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
__func__, ob->id.name, ob, "pchan", pchan->name, pchan);
BLI_assert(ob->type == OB_ARMATURE);
@@ -636,8 +650,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
- bPoseChannel *pchan)
+ int pchan_index)
{
+ bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
__func__, ob->id.name, ob, "pchan", pchan->name, pchan);
bArmature *arm = (bArmature *)ob->data;
@@ -656,8 +671,10 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
}
void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
- bPoseChannel *pchan)
+ struct Object *ob,
+ int pchan_index)
{
+ bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
float imat[4][4];
DEG_debug_print_eval(__func__, pchan->name, pchan);
if (pchan->bone) {
@@ -669,8 +686,9 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
- bPoseChannel *rootchan)
+ int rootchan_index)
{
+ bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
__func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
@@ -685,9 +703,10 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
- bPoseChannel *rootchan)
+ int rootchan_index)
{
+ bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
__func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
@@ -701,17 +720,23 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
- Object *ob,
- bPose *UNUSED(pose))
+ Object *ob)
{
+ bPose *pose = ob->pose;
+ BLI_assert(pose != NULL);
+
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
- /* 6. release the IK tree */
+ /* release the IK tree */
BIK_release_tree(scene, ob, ctime);
ob->recalc &= ~OB_RECALC_ALL;
+
+ BLI_assert(pose->chan_array != NULL);
+ MEM_freeN(pose->chan_array);
+ pose->chan_array = NULL;
}
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 4efca5bcc41..6b31c8c96f9 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -42,28 +42,19 @@
#include "DNA_scene_types.h"
-#include "BLI_fileops.h"
-#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "IMB_imbuf.h"
-#include "IMB_moviecache.h"
-
#include "BKE_blender_undo.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_appdir.h"
-#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
-#include "BKE_image.h"
#include "BKE_main.h"
-#include "RE_pipeline.h"
#include "BLO_undofile.h"
-#include "BLO_readfile.h"
#include "BLO_writefile.h"
/* -------------------------------------------------------------------- */
@@ -73,46 +64,21 @@
#define UNDO_DISK 0
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- /* Only for 'UNDO_DISK' */
- char filename[FILE_MAX];
- char name[BKE_UNDO_STR_MAX];
- MemFile memfile;
- size_t undo_size;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
-
-/**
- * Avoid bad-level call to #WM_jobs_kill_all_except()
- */
-static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL;
-
-void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C))
-{
- undo_wm_job_kill_callback = callback;
-}
-
-static int read_undosave(bContext *C, UndoElem *uel)
+bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
{
char mainstr[sizeof(G.main->name)];
int success = 0, fileflags;
- /* This is needed so undoing/redoing doesn't crash with threaded previews going */
- undo_wm_job_kill_callback(C);
-
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
fileflags = G.fileflags;
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK) {
- success = (BKE_blendfile_read(C, uel->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
+ success = (BKE_blendfile_read(C, mfu->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
}
else {
- success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0);
+ success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, NULL, 0);
}
/* restore */
@@ -127,51 +93,9 @@ static int read_undosave(bContext *C, UndoElem *uel)
return success;
}
-/* name can be a dynamic string */
-void BKE_undo_write(bContext *C, const char *name)
+MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
{
- int nr /*, success */ /* UNUSED */;
- UndoElem *uel;
-
- if ((U.uiflag & USER_GLOBALUNDO) == 0) {
- return;
- }
-
- if (U.undosteps == 0) {
- return;
- }
-
- /* remove all undos after (also when curundo == NULL) */
- while (undobase.last != curundo) {
- uel = undobase.last;
- BLI_remlink(&undobase, uel);
- BLO_memfile_free(&uel->memfile);
- MEM_freeN(uel);
- }
-
- /* make new */
- curundo = uel = MEM_callocN(sizeof(UndoElem), "undo file");
- BLI_strncpy(uel->name, name, sizeof(uel->name));
- BLI_addtail(&undobase, uel);
-
- /* and limit amount to the maximum */
- nr = 0;
- uel = undobase.last;
- while (uel) {
- nr++;
- if (nr == U.undosteps) break;
- uel = uel->prev;
- }
- if (uel) {
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
- BLI_remlink(&undobase, first);
- /* the merge is because of compression */
- BLO_memfile_merge(&first->memfile, &first->next->memfile);
- MEM_freeN(first);
- }
- }
-
+ MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__);
/* disk save version */
if (UNDO_DISK) {
@@ -187,222 +111,25 @@ void BKE_undo_write(bContext *C, const char *name)
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr);
- /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL);
+ /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL);
- BLI_strncpy(curundo->filename, filename, sizeof(curundo->filename));
+ BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
}
else {
- MemFile *prevfile = NULL;
-
- if (curundo->prev) prevfile = &(curundo->prev->memfile);
-
- /* success = */ /* UNUSED */ BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags);
- curundo->undo_size = curundo->memfile.size;
- }
-
- if (U.undomemory != 0) {
- size_t maxmem, totmem;
- /* limit to maximum memory (afterwards, we can't know in advance) */
- totmem = 0;
- maxmem = ((size_t)U.undomemory) * 1024 * 1024;
-
- /* keep at least two (original + other) */
- uel = undobase.last;
- while (uel && uel->prev) {
- totmem += uel->undo_size;
- if (totmem > maxmem) break;
- uel = uel->prev;
- }
-
- if (uel) {
- if (uel->prev && uel->prev->prev)
- uel = uel->prev;
-
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
- BLI_remlink(&undobase, first);
- /* the merge is because of compression */
- BLO_memfile_merge(&first->memfile, &first->next->memfile);
- MEM_freeN(first);
- }
- }
- }
-}
-
-/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
-void BKE_undo_step(bContext *C, int step)
-{
-
- if (step == 0) {
- read_undosave(C, curundo);
- }
- else if (step == 1) {
- /* curundo should never be NULL, after restart or load file it should call undo_save */
- if (curundo == NULL || curundo->prev == NULL) {
- // XXX error("No undo available");
- }
- else {
- if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
- curundo = curundo->prev;
- read_undosave(C, curundo);
- }
- }
- else {
- /* curundo has to remain current situation! */
-
- if (curundo == NULL || curundo->next == NULL) {
- // XXX error("No redo available");
- }
- else {
- read_undosave(C, curundo->next);
- curundo = curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name);
- }
- }
-}
-
-void BKE_undo_reset(void)
-{
- UndoElem *uel;
-
- uel = undobase.first;
- while (uel) {
- BLO_memfile_free(&uel->memfile);
- uel = uel->next;
- }
-
- BLI_freelistN(&undobase);
- curundo = NULL;
-}
-
-/* based on index nr it does a restore */
-void BKE_undo_number(bContext *C, int nr)
-{
- curundo = BLI_findlink(&undobase, nr);
- BKE_undo_step(C, 0);
-}
-
-/* go back to the last occurance of name in stack */
-void BKE_undo_name(bContext *C, const char *name)
-{
- UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
-
- if (uel && uel->prev) {
- curundo = uel->prev;
- BKE_undo_step(C, 0);
- }
-}
-
-/* name optional */
-bool BKE_undo_is_valid(const char *name)
-{
- if (name) {
- UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
- return uel && uel->prev;
+ MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
+ /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
+ mfu->undo_size = mfu->memfile.size;
}
- return undobase.last != undobase.first;
-}
-
-/* get name of undo item, return null if no item with this index */
-/* if active pointer, set it to 1 if true */
-const char *BKE_undo_get_name(int nr, bool *r_active)
-{
- UndoElem *uel = BLI_findlink(&undobase, nr);
+ bmain->is_memfile_undo_written = true;
- if (r_active) *r_active = false;
-
- if (uel) {
- if (r_active && (uel == curundo)) {
- *r_active = true;
- }
- return uel->name;
- }
- return NULL;
+ return mfu;
}
-/* return the name of the last item */
-const char *BKE_undo_get_name_last(void)
+void BKE_memfile_undo_free(MemFileUndoData *mfu)
{
- UndoElem *uel = undobase.last;
- return (uel ? uel->name : NULL);
-}
-
-/**
- * Saves .blend using undo buffer.
- *
- * \return success.
- */
-bool BKE_undo_save_file(const char *filename)
-{
- UndoElem *uel;
- MemFileChunk *chunk;
- int file, oflags;
-
- if ((U.uiflag & USER_GLOBALUNDO) == 0) {
- return false;
- }
-
- uel = curundo;
- if (uel == NULL) {
- fprintf(stderr, "No undo buffer to save recovery file\n");
- return false;
- }
-
- /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK,
- * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks.
- */
-
- oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC;
-#ifdef O_NOFOLLOW
- /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */
- oflags |= O_NOFOLLOW;
-#else
- /* TODO(sergey): How to deal with symlinks on windows? */
-# ifndef _MSC_VER
-# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103"
-# endif
-#endif
- file = BLI_open(filename, oflags, 0666);
-
- if (file == -1) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- filename, errno ? strerror(errno) : "Unknown error opening file");
- return false;
- }
-
- for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) {
- if (write(file, chunk->buf, chunk->size) != chunk->size) {
- break;
- }
- }
-
- close(file);
-
- if (chunk) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- filename, errno ? strerror(errno) : "Unknown error writing file");
- return false;
- }
- return true;
-}
-
-/* sets curscene */
-Main *BKE_undo_get_main(Scene **r_scene)
-{
- Main *mainp = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE);
-
- if (bfd) {
- mainp = bfd->main;
- if (r_scene) {
- *r_scene = bfd->curscene;
- }
-
- MEM_freeN(bfd);
- }
-
- return mainp;
+ BLO_memfile_free(&mfu->memfile);
+ MEM_freeN(mfu);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 8b7118db151..058394fc1b1 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -42,7 +42,6 @@
#include "BKE_animsys.h"
#include "BKE_cachefile.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 719125b3317..132cbd07ac3 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -47,7 +47,6 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_object.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 2a300cbe47b..8433634f749 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -297,7 +297,10 @@ bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, i
}
/* ****************** make displists ********************* */
-
+#ifdef __INTEL_COMPILER
+/* ICC with the optimization -02 causes crashes. */
+# pragma intel optimization_level 1
+#endif
static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
const bool for_render, const bool use_render_resolution)
{
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 30ead3ffbb6..7dc6e3575b2 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -54,7 +54,6 @@
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_fluidsim.h"
-#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 64f25cdcf53..e8b5ce77613 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -46,6 +46,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
+#include "IMB_metadata.h"
#ifdef WITH_OPENEXR
# include "intern/openexr/openexr_multi.h"
@@ -151,7 +152,7 @@ static void imagecache_put(Image *image, int index, ImBuf *ibuf)
if (image->cache == NULL) {
// char cache_name[64];
- // BLI_snprintf(cache_name, sizeof(cache_name), "Image Datablock %s", image->id.name);
+ // SNPRINTF(cache_name, "Image Datablock %s", image->id.name);
image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey),
imagecache_hashhash, imagecache_hashcmp);
@@ -436,7 +437,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
BLI_listbase_clear(lb_dst);
for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
- BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath));
+ STRNCPY(imapf_dst->filepath, imapf_src->filepath);
if (imapf_src->packedfile)
imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
@@ -592,7 +593,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
int file;
char str[FILE_MAX];
- BLI_strncpy(str, filepath, sizeof(str));
+ STRNCPY(str, filepath);
BLI_path_abs(str, bmain->name);
/* exists? */
@@ -602,7 +603,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
close(file);
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
- BLI_strncpy(ima->name, filepath, sizeof(ima->name));
+ STRNCPY(ima->name, filepath);
if (BLI_testextensie_array(filepath, imb_ext_movie))
ima->source = IMA_SRC_MOVIE;
@@ -621,13 +622,13 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
Image *ima;
char str[FILE_MAX], strtest[FILE_MAX];
- BLI_strncpy(str, filepath, sizeof(str));
+ STRNCPY(str, filepath);
BLI_path_abs(str, G.main->name);
/* first search an identical filepath */
for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
- BLI_strncpy(strtest, ima->name, sizeof(ima->name));
+ STRNCPY(strtest, ima->name);
BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id));
if (BLI_path_cmp(strtest, str) == 0) {
@@ -668,7 +669,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
if (colorspace_settings->name[0] == '\0') {
const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT);
- BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name));
+ STRNCPY(colorspace_settings->name, colorspace);
}
if (ibuf != NULL) {
@@ -682,7 +683,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
if (colorspace_settings->name[0] == '\0') {
const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
- BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name));
+ STRNCPY(colorspace_settings->name, colorspace);
}
if (ibuf != NULL) {
@@ -695,7 +696,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
return NULL;
}
- BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
+ STRNCPY(ibuf->name, name);
ibuf->userflags |= IB_BITMAPDIRTY;
switch (gen_type) {
@@ -725,7 +726,7 @@ Image *BKE_image_add_generated(
int view_id;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
- /* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */
+ /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
ima->gen_y = height;
ima->gen_type = gen_type;
@@ -766,7 +767,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name)
ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
if (ima) {
- BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
+ STRNCPY(ima->name, ibuf->name);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
ima->ok = IMA_OK_LOADED;
}
@@ -812,7 +813,7 @@ static void image_memorypack_multiview(Image *ima)
pf->size = ibuf->encodedsize;
imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
- BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, iv->filepath);
imapf->packedfile = pf;
BLI_addtail(&ima->packedfiles, imapf);
@@ -862,7 +863,7 @@ void BKE_image_memorypack(Image *ima)
pf->size = ibuf->encodedsize;
imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
- BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, ima->name);
imapf->packedfile = pf;
BLI_addtail(&ima->packedfiles, imapf);
@@ -888,7 +889,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = newPackedFile(reports, ima->name, basepath);
if (imapf->packedfile) {
- BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, ima->name);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
@@ -902,7 +903,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
if (imapf->packedfile) {
- BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, iv->filepath);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
@@ -922,7 +923,7 @@ void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, c
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = newPackedFileMemory(data, data_len);
- BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, ima->name);
}
}
@@ -1622,6 +1623,7 @@ typedef struct StampData {
char marker[512];
char time[512];
char frame[512];
+ char frame_range[512];
char camera[STAMP_NAME_SIZE];
char cameralens[STAMP_NAME_SIZE];
char scene[STAMP_NAME_SIZE];
@@ -1638,14 +1640,19 @@ typedef struct StampData {
} StampData;
#undef STAMP_NAME_SIZE
-static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix)
+/**
+ * \param do_prefix: Include a label like "File ", "Date ", etc. in the stamp data strings.
+ * \param use_dynamic: Also include data that can change on a per-frame basis.
+ */
+static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix,
+ bool use_dynamic)
{
char text[256];
struct tm *tl;
time_t t;
if (scene->r.stamp & R_STAMP_FILENAME) {
- BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>");
+ SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>");
}
else {
stamp_data->file[0] = '\0';
@@ -1653,7 +1660,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
if (scene->r.stamp & R_STAMP_NOTE) {
/* Never do prefix for Note */
- BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", scene->r.stamp_udata);
+ SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata);
}
else {
stamp_data->note[0] = '\0';
@@ -1662,83 +1669,93 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
if (scene->r.stamp & R_STAMP_DATE) {
t = time(NULL);
tl = localtime(&t);
- BLI_snprintf(text, sizeof(text), "%04d/%02d/%02d %02d:%02d:%02d", tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec);
- BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), do_prefix ? "Date %s" : "%s", text);
+ SNPRINTF(text, "%04d/%02d/%02d %02d:%02d:%02d",
+ tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec);
+ SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text);
}
else {
stamp_data->date[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_MARKER) {
+ if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) {
const char *name = BKE_scene_find_last_marker_name(scene, CFRA);
- if (name) BLI_strncpy(text, name, sizeof(text));
- else BLI_strncpy(text, "<none>", sizeof(text));
+ if (name) STRNCPY(text, name);
+ else STRNCPY(text, "<none>");
- BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), do_prefix ? "Marker %s" : "%s", text);
+ SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text);
}
else {
stamp_data->marker[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_TIME) {
+ if (use_dynamic && scene->r.stamp & R_STAMP_TIME) {
const short timecode_style = USER_TIMECODE_SMPTE_FULL;
BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style);
- BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Timecode %s" : "%s", text);
+ SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text);
}
else {
stamp_data->time[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_FRAME) {
+ if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) {
char fmtstr[32];
int digits = 1;
if (scene->r.efra > 9)
digits = integer_digits_i(scene->r.efra);
- BLI_snprintf(fmtstr, sizeof(fmtstr), do_prefix ? "Frame %%0%di" : "%%0%di", digits);
- BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), fmtstr, scene->r.cfra);
+ SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits);
+ SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra);
}
else {
stamp_data->frame[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_CAMERA) {
- BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>");
+ if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
+ SNPRINTF(stamp_data->frame_range,
+ do_prefix ? "Frame Range %d:%d" : "%d:%d",
+ scene->r.sfra, scene->r.efra);
+ }
+ else {
+ stamp_data->frame_range[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) {
+ SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>");
}
else {
stamp_data->camera[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_CAMERALENS) {
+ if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) {
if (camera && camera->type == OB_CAMERA) {
- BLI_snprintf(text, sizeof(text), "%.2f", ((Camera *)camera->data)->lens);
+ SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens);
}
else {
- BLI_strncpy(text, "<none>", sizeof(text));
+ STRNCPY(text, "<none>");
}
- BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), do_prefix ? "Lens %s" : "%s", text);
+ SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text);
}
else {
stamp_data->cameralens[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SCENE) {
- BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), do_prefix ? "Scene %s" : "%s", scene->id.name + 2);
+ SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2);
}
else {
stamp_data->scene[0] = '\0';
}
- if (scene->r.stamp & R_STAMP_SEQSTRIP) {
+ if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) {
Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra);
- if (seq) BLI_strncpy(text, seq->name + 2, sizeof(text));
- else BLI_strncpy(text, "<none>", sizeof(text));
+ if (seq) STRNCPY(text, seq->name + 2);
+ else STRNCPY(text, "<none>");
- BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), do_prefix ? "Strip %s" : "%s", text);
+ SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text);
}
else {
stamp_data->strip[0] = '\0';
@@ -1748,22 +1765,29 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
Render *re = RE_GetSceneRender(scene);
RenderStats *stats = re ? RE_GetStats(re) : NULL;
- if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
+ if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime);
- BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), do_prefix ? "RenderTime %s" : "%s", text);
+ SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text);
}
else {
stamp_data->rendertime[0] = '\0';
}
- if (stats && (scene->r.stamp & R_STAMP_MEMORY)) {
- BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
}
else {
stamp_data->memory[0] = '\0';
}
}
+ if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
+ SNPRINTF(stamp_data->frame_range,
+ do_prefix ? "Frame Range %d:%d" : "%d:%d", scene->r.sfra, scene->r.efra);
+ }
+ else {
+ stamp_data->frame_range[0] = '\0';
+ }
}
/* Will always add prefix. */
@@ -1772,73 +1796,73 @@ static void stampdata_from_template(StampData *stamp_data,
const StampData *stamp_data_template)
{
if (scene->r.stamp & R_STAMP_FILENAME) {
- BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), "File %s", stamp_data_template->file);
+ SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
}
else {
stamp_data->file[0] = '\0';
}
if (scene->r.stamp & R_STAMP_NOTE) {
- BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", stamp_data_template->note);
+ SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
}
else {
stamp_data->note[0] = '\0';
}
if (scene->r.stamp & R_STAMP_DATE) {
- BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), "Date %s", stamp_data_template->date);
+ SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
}
else {
stamp_data->date[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MARKER) {
- BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), "Marker %s", stamp_data_template->marker);
+ SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
}
else {
stamp_data->marker[0] = '\0';
}
if (scene->r.stamp & R_STAMP_TIME) {
- BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), "Timecode %s", stamp_data_template->time);
+ SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
}
else {
stamp_data->time[0] = '\0';
}
if (scene->r.stamp & R_STAMP_FRAME) {
- BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), "Frame %s", stamp_data_template->frame);
+ SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
}
else {
stamp_data->frame[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERA) {
- BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), "Camera %s", stamp_data_template->camera);
+ SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
}
else {
stamp_data->camera[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERALENS) {
- BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), "Lens %s", stamp_data_template->cameralens);
+ SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
}
else {
stamp_data->cameralens[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SCENE) {
- BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), "Scene %s", stamp_data_template->scene);
+ SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
}
else {
stamp_data->scene[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SEQSTRIP) {
- BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), "Strip %s", stamp_data_template->strip);
+ SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
}
else {
stamp_data->strip[0] = '\0';
}
if (scene->r.stamp & R_STAMP_RENDERTIME) {
- BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), "RenderTime %s", stamp_data_template->rendertime);
+ SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
}
else {
stamp_data->rendertime[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MEMORY) {
- BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory);
+ SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
}
else {
stamp_data->memory[0] = '\0';
@@ -1884,7 +1908,7 @@ void BKE_image_stamp_buf(
display = IMB_colormanagement_display_get_named(display_device);
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0);
+ stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
}
else {
stampdata_from_template(&stamp_data, scene, stamp_data_template);
@@ -2105,13 +2129,28 @@ void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderRes
}
if (!allocate_only)
- stampdata(scene, camera, stamp_data, 0);
+ stampdata(scene, camera, stamp_data, 0, true);
if (!rr->stamp_data) {
rr->stamp_data = stamp_data;
}
}
+struct StampData *BKE_stamp_info_from_scene_static(Scene *scene)
+{
+ struct StampData *stamp_data;
+
+ if (!(scene && (scene->r.stamp & R_STAMP_ALL)))
+ return NULL;
+
+ /* Memory is allocated here (instead of by the caller) so that the caller
+ * doesn't have to know the size of the StampData struct. */
+ stamp_data = MEM_callocN(sizeof(StampData), __func__);
+ stampdata(scene, NULL, stamp_data, 0, false);
+
+ return stamp_data;
+}
+
void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip)
{
if ((callback == NULL) || (stamp_data == NULL)) {
@@ -2129,6 +2168,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall
CALL(marker, "Marker");
CALL(time, "Time");
CALL(frame, "Frame");
+ CALL(frame_range, "FrameRange");
CALL(camera, "Camera");
CALL(cameralens, "Lens");
CALL(scene, "Scene");
@@ -2157,8 +2197,8 @@ void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char
stamp_data = rr->stamp_data;
StampDataCustomField *field = MEM_mallocN(sizeof(StampDataCustomField),
"StampData Custom Field");
- BLI_strncpy(field->key, key, sizeof(field->key));
- BLI_strncpy(field->value, value, sizeof(field->value));
+ STRNCPY(field->key, key);
+ STRNCPY(field->value, value);
BLI_addtail(&stamp_data->custom_fields, field);
}
@@ -2172,27 +2212,31 @@ void BKE_stamp_data_free(struct StampData *stamp_data)
}
/* wrap for callback only */
-static void metadata_change_field(void *data, const char *propname, char *propvalue, int UNUSED(len))
+static void metadata_set_field(void *data, const char *propname, char *propvalue, int UNUSED(len))
{
- IMB_metadata_change_field(data, propname, propvalue);
+ /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
+ struct ImBuf *imbuf = data;
+ IMB_metadata_set_field(imbuf->metadata, propname, propvalue);
}
static void metadata_get_field(void *data, const char *propname, char *propvalue, int len)
{
- IMB_metadata_get_field(data, propname, propvalue, len);
+ /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
+ struct ImBuf *imbuf = data;
+ IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len);
}
void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
{
struct StampData *stamp_data = rr->stamp_data;
-
- BKE_stamp_info_callback(ibuf, stamp_data, metadata_change_field, false);
+ IMB_metadata_ensure(&ibuf->metadata);
+ BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false);
}
void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf)
{
struct StampData *stamp_data = rr->stamp_data;
-
+ IMB_metadata_ensure(&ibuf->metadata);
BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true);
}
@@ -2739,7 +2783,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
if (BKE_image_has_packedfile(ima)) {
const int totfiles = image_num_files(ima);
- if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
/* in case there are new available files to be loaded */
image_free_packedfiles(ima);
BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id));
@@ -2894,7 +2938,7 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
iuser->multi_index = iuser->multiview_eye;
}
else {
- if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) {
+ if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1))) {
iuser->multi_index = iuser->view = 0;
}
else {
@@ -2957,7 +3001,7 @@ static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
if (rr) {
for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
- BLI_strncpy(iv->name, rv->name, sizeof(iv->name));
+ STRNCPY(iv->name, rv->name);
BLI_addtail(&ima->views, iv);
}
}
@@ -3038,8 +3082,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
ImageView *iv;
iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
- BLI_strncpy(iv->name, viewname, sizeof(iv->name));
- BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath));
+ STRNCPY(iv->name, viewname);
+ STRNCPY(iv->filepath, filepath);
/* For stereo drawing we need to ensure:
* STEREO_LEFT_NAME == STEREO_LEFT_ID and
@@ -3361,7 +3405,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
const int totfiles = image_num_files(ima);
int i;
- if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) {
+ if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
image_free_anims(ima);
for (i = 0; i < totfiles; i++) {
@@ -3489,7 +3533,7 @@ static ImBuf *load_image_single(
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
BLI_addtail(&ima->packedfiles, imapf);
- BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath));
+ STRNCPY(imapf->filepath, filepath);
imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id));
}
}
@@ -3517,7 +3561,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
/* this should never happen, but just playing safe */
if (has_packed) {
- if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
image_free_packedfiles(ima);
has_packed = false;
}
@@ -4644,7 +4688,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
for (srv = scene->r.views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
char filepath[FILE_MAX];
- BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext);
+ SNPRINTF(filepath, "%s%s%s", prefix, srv->suffix, ext);
image_add_view(ima, srv->name, filepath);
}
}
@@ -4655,7 +4699,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
int file;
char str[FILE_MAX];
- BLI_strncpy(str, iv->filepath, sizeof(str));
+ STRNCPY(str, iv->filepath);
BLI_path_abs(str, G.main->name);
/* exists? */
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 3a4c920d8fb..2714c4f43a1 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -47,7 +47,6 @@
#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_icons.h"
-#include "BKE_global.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index ea4c3f380ff..4b9748133d7 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -55,7 +55,6 @@
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_displist.h"
-#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 99423ee26a6..10b724f9f69 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -757,6 +757,7 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
new_id(lb, id, NULL);
/* alphabetic insertion: is in new_id */
id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
+ bmain->is_memfile_undo_written = false;
BKE_main_unlock(bmain);
}
@@ -776,6 +777,7 @@ void BKE_libblock_management_main_remove(Main *bmain, void *idv)
BKE_main_lock(bmain);
BLI_remlink(lb, id);
id->tag |= LIB_TAG_NO_MAIN;
+ bmain->is_memfile_undo_written = false;
BKE_main_unlock(bmain);
}
@@ -1138,6 +1140,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
BKE_main_lock(bmain);
BLI_addtail(lb, id);
new_id(lb, id, name);
+ bmain->is_memfile_undo_written = false;
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 878f38256b4..e00884c8a9d 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -47,7 +47,6 @@
#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index ff4e7f36018..b5742dbdbb7 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -52,7 +52,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 889f65da689..e2a9691e577 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -43,7 +43,6 @@
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c8b44511edd..6a45432e863 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2429,7 +2429,7 @@ Mesh *BKE_mesh_new_from_object(
/* if getting the original caged mesh, delete object modifiers */
if (cage)
- BKE_object_free_modifiers(tmpobj);
+ BKE_object_free_modifiers(tmpobj, 0);
/* copies the data */
copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index d7a24f90dbe..ce04f3c31e2 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -136,16 +136,38 @@ ModifierData *modifier_new(int type)
return md;
}
-void modifier_free(ModifierData *md)
+static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void modifier_free_ex(ModifierData *md, const int flag)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
if (mti->freeData) mti->freeData(md);
if (md->error) MEM_freeN(md->error);
MEM_freeN(md);
}
+void modifier_free(ModifierData *md)
+{
+ modifier_free_ex(md, 0);
+}
+
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
if (modifiers && md) {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index acc652fb1be..751cd733ae1 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -201,12 +201,12 @@ void BKE_object_free_curve_cache(Object *ob)
}
}
-void BKE_object_free_modifiers(Object *ob)
+void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
while ((md = BLI_pophead(&ob->modifiers))) {
- modifier_free(md);
+ modifier_free_ex(md, flag);
}
/* particle modifiers were freed, so free the particlesystems as well */
@@ -268,7 +268,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
- BKE_object_free_modifiers(ob_dst);
+ BKE_object_free_modifiers(ob_dst, 0);
if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
/* only objects listed above can have modifiers and linking them to objects
@@ -410,7 +410,8 @@ void BKE_object_free(Object *ob)
{
BKE_animdata_free((ID *)ob, false);
- BKE_object_free_modifiers(ob);
+ /* BKE_<id>_free shall never touch to ID->us. Never ever. */
+ BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index d0bf1bed4f4..bee6e7d3df0 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -373,7 +373,7 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde
/* remove colour from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
- if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) {
+ if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) == palette->active_color) {
palette->active_color--;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index d7e08233601..04c365eee76 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3165,7 +3165,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n
psys->part = BKE_particlesettings_add(NULL, DATA_("ParticleSettings"));
- if (BLI_listbase_count_ex(&ob->particlesystem, 2) > 1)
+ if (BLI_listbase_count_at_most(&ob->particlesystem, 2) > 1)
BLI_snprintf(psys->name, sizeof(psys->name), DATA_("ParticleSystem %i"), BLI_listbase_count(&ob->particlesystem));
else
BLI_strncpy(psys->name, DATA_("ParticleSystem"), sizeof(psys->name));
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 1a18528ba84..8aeeee5a1ad 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -76,7 +76,6 @@
#include "BKE_effect.h"
#include "BKE_library_query.h"
#include "BKE_particle.h"
-#include "BKE_global.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 6b6f2605dc3..e32a5d0681e 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -555,9 +555,9 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
#endif
#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
- (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n)
+ (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n)
-static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
+static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
{
int count = 0;
BMFace *f;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index c10f54a99eb..b8873cca0fb 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -700,6 +700,39 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* --------------------- */
+static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float))
+{
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
+}
+
/**
* Create physics sim representation of constraint given rigid body constraint settings
*
@@ -818,40 +851,13 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
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);
- ATTR_FALLTHROUGH;
- case RBC_TYPE_6DOF:
- if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */
- rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring);
+ break;
+ case RBC_TYPE_6DOF:
+ rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
- else
- RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
break;
case RBC_TYPE_MOTOR:
rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2);
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index ee80438db64..49f120de250 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -52,6 +52,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
+#include "IMB_metadata.h"
#include "BLI_math_color_blend.h"
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 67a64ab1433..0cc151c3645 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -84,6 +84,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
+#include "IMB_metadata.h"
#include "BKE_context.h"
#include "BKE_sound.h"
@@ -942,6 +943,8 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
return;
}
+ IMB_anim_load_metadata(sanim->anim);
+
seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
@@ -2955,7 +2958,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq
int totviews;
int i;
- if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1))
+ if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1))
goto monoview_movie;
totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
@@ -5381,6 +5384,8 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
}
+ IMB_anim_load_metadata(anim_arr[0]);
+
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index bf473603c0e..e12b981a8f9 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -72,7 +72,6 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
#include "BKE_effect.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 9d604a9382a..1d2e12f34ac 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -32,7 +32,6 @@
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index b8307031920..c7588a4ed48 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -168,9 +168,9 @@ enum {
static void txt_pop_first(Text *text);
static void txt_pop_last(Text *text);
-static void txt_undo_add_blockop(Text *text, int op, const char *buf);
+static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf);
static void txt_delete_line(Text *text, TextLine *line);
-static void txt_delete_sel(Text *text);
+static void txt_delete_sel(Text *text, TextUndoBuf *utxt);
static void txt_make_dirty(Text *text);
/***/
@@ -188,13 +188,6 @@ int txt_get_undostate(void)
return undoing;
}
-static void init_undo_text(Text *text)
-{
- text->undo_pos = -1;
- text->undo_len = 0;
- text->undo_buf = NULL;
-}
-
/**
* \note caller must handle `undo_buf` and `compiled` members.
*/
@@ -222,7 +215,6 @@ void BKE_text_free(Text *text)
BKE_text_free_lines(text);
MEM_SAFE_FREE(text->name);
- MEM_SAFE_FREE(text->undo_buf);
#ifdef WITH_PYTHON
BPY_text_free_code(text);
#endif
@@ -236,8 +228,6 @@ void BKE_text_init(Text *ta)
ta->name = NULL;
- init_undo_text(ta);
-
ta->nlines = 1;
ta->flags = TXT_ISDIRTY | TXT_ISMEM;
if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
@@ -419,10 +409,6 @@ bool BKE_text_reload(Text *text)
txt_make_dirty(text);
/* clear undo buffer */
- MEM_freeN(text->undo_buf);
- init_undo_text(text);
-
-
if (BLI_stat(filepath_abs, &st) != -1) {
text->mtime = st.st_mtime;
}
@@ -471,8 +457,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
}
/* clear undo buffer */
- init_undo_text(ta);
-
if (BLI_stat(filepath_abs, &st) != -1) {
ta->mtime = st.st_mtime;
}
@@ -526,8 +510,6 @@ void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, c
ta_dst->curl = ta_dst->sell = ta_dst->lines.first;
ta_dst->curc = ta_dst->selc = 0;
-
- init_undo_text(ta_dst);
}
Text *BKE_text_copy(Main *bmain, const Text *ta)
@@ -542,25 +524,29 @@ void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
}
-void BKE_text_clear(Text *text) /* called directly from rna */
+void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */
{
int oldstate;
- oldstate = txt_get_undostate();
- txt_set_undostate(1);
+ if (utxt) {
+ oldstate = txt_get_undostate();
+ }
+ txt_set_undostate(utxt != NULL);
+
txt_sel_all(text);
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
+
txt_set_undostate(oldstate);
txt_make_dirty(text);
}
-void BKE_text_write(Text *text, const char *str) /* called directly from rna */
+void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */
{
int oldstate;
oldstate = txt_get_undostate();
- txt_insert_buf(text, str);
+ txt_insert_buf(text, utxt, str);
txt_move_eof(text, 0);
txt_set_undostate(oldstate);
@@ -1153,7 +1139,7 @@ bool txt_has_sel(Text *text)
return ((text->curl != text->sell) || (text->curc != text->selc));
}
-static void txt_delete_sel(Text *text)
+static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
{
TextLine *tmpl;
char *buf;
@@ -1167,7 +1153,7 @@ static void txt_delete_sel(Text *text)
if (!undoing) {
buf = txt_sel_to_buf(text);
- txt_undo_add_blockop(text, UNDO_DBLOCK, buf);
+ txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf);
MEM_freeN(buf);
}
@@ -1408,7 +1394,7 @@ char *txt_sel_to_buf(Text *text)
return buf;
}
-void txt_insert_buf(Text *text, const char *in_buffer)
+void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
{
int l = 0, u, len;
size_t i = 0, j;
@@ -1417,22 +1403,22 @@ void txt_insert_buf(Text *text, const char *in_buffer)
if (!in_buffer) return;
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
len = strlen(in_buffer);
buffer = BLI_strdupn(in_buffer, len);
len += txt_extended_ascii_as_utf8(&buffer);
- if (!undoing) txt_undo_add_blockop(text, UNDO_IBLOCK, buffer);
+ if (!undoing) txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer);
u = undoing;
undoing = 1;
/* Read the first line (or as close as possible */
while (buffer[i] && buffer[i] != '\n')
- txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i));
+ txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i));
- if (buffer[i] == '\n') txt_split_curline(text);
+ if (buffer[i] == '\n') txt_split_curline(text, utxt);
else { undoing = u; MEM_freeN(buffer); return; }
i++;
@@ -1450,7 +1436,7 @@ void txt_insert_buf(Text *text, const char *in_buffer)
}
else {
for (j = i - l; j < i && j < len; )
- txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j));
+ txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j));
break;
}
}
@@ -1464,7 +1450,7 @@ void txt_insert_buf(Text *text, const char *in_buffer)
/* Undo functions */
/******************/
-static bool max_undo_test(Text *text, int x)
+static bool max_undo_test(TextUndoBuf *utxt, int x)
{
/* Normally over-allocating is preferred,
* however in this case the buffer is small enough and re-allocation
@@ -1474,25 +1460,24 @@ static bool max_undo_test(Text *text, int x)
*/
/* Add one for the null terminator. */
- text->undo_len = text->undo_pos + x + 1;
- if (text->undo_len > TXT_MAX_UNDO) {
+ utxt->len = utxt->pos + x + 1;
+ if (utxt->len > TXT_MAX_UNDO) {
/* XXX error("Undo limit reached, buffer cleared\n"); */
- MEM_freeN(text->undo_buf);
- init_undo_text(text);
+ MEM_freeN(utxt->buf);
return false;
}
else {
/* Small reallocations on each undo step is fine. */
- text->undo_buf = MEM_recallocN(text->undo_buf, text->undo_len);
+ utxt->buf = MEM_recallocN(utxt->buf, utxt->len);
}
return true;
}
-static void txt_undo_end(Text *text)
+static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt)
{
- int undo_pos_end = text->undo_pos + 1;
- BLI_assert(undo_pos_end + 1 == text->undo_len);
- text->undo_buf[undo_pos_end] = '\0';
+ int undo_pos_end = utxt->pos + 1;
+ BLI_assert(undo_pos_end + 1 == utxt->len);
+ utxt->buf[undo_pos_end] = '\0';
}
/* Call once undo is done. */
@@ -1501,11 +1486,11 @@ static void txt_undo_end(Text *text)
#endif
#if 0 /* UNUSED */
-static void dump_buffer(Text *text)
+static void dump_buffer(TextUndoBuf *utxt)
{
int i = 0;
-
- while (i++ < text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
+
+ while (i++ < utxt->undo_pos) printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]);
}
/* Note: this function is outdated and must be updated if needed for future use */
@@ -1520,10 +1505,10 @@ void txt_print_undo(Text *text)
printf("---< Undo Buffer >---\n");
- printf("UndoPosition is %d\n", text->undo_pos);
+ printf("UndoPosition is %d\n", utxt->pos);
- while (i <= text->undo_pos) {
- op = text->undo_buf[i];
+ while (i <= utxt->pos) {
+ op = utxt->buf[i];
if (op == UNDO_INSERT_1) {
ops = "Insert ascii ";
@@ -1589,15 +1574,15 @@ void txt_print_undo(Text *text)
printf(" - Char is ");
switch (op) {
case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
- printf("%c", text->undo_buf[i]);
+ printf("%c", utxt->buf[i]);
i++;
break;
case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
- printf("%c%c", text->undo_buf[i], text->undo_buf[i + 1]);
+ printf("%c%c", utxt->buf[i], utxt->buf[i + 1]);
i += 2;
break;
case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
- printf("%c%c%c", text->undo_buf[i], text->undo_buf[i + 1], text->undo_buf[i + 2]);
+ printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]);
i += 3;
break;
case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4:
@@ -1605,10 +1590,10 @@ void txt_print_undo(Text *text)
unsigned int uc;
char c[BLI_UTF8_MAX + 1];
size_t c_len;
- uc = text->undo_buf[i]; i++;
- uc = uc + (text->undo_buf[i] << 8); i++;
- uc = uc + (text->undo_buf[i] << 16); i++;
- uc = uc + (text->undo_buf[i] << 24); i++;
+ uc = utxt->buf[i]; i++;
+ uc = uc + (utxt->buf[i] << 8); i++;
+ uc = uc + (utxt->buf[i] << 16); i++;
+ uc = uc + (utxt->buf[i] << 24); i++;
c_len = BLI_str_utf8_from_unicode(uc, c);
c[c_len] = '\0';
puts(c);
@@ -1619,44 +1604,44 @@ void txt_print_undo(Text *text)
else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) {
i++;
- linep = text->undo_buf[i]; i++;
- linep = linep + (text->undo_buf[i] << 8); i++;
- linep = linep + (text->undo_buf[i] << 16); i++;
- linep = linep + (text->undo_buf[i] << 24); i++;
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
printf(" (length %d) <", linep);
while (linep > 0) {
- putchar(text->undo_buf[i]);
+ putchar(utxt->buf[i]);
linep--; i++;
}
- linep = text->undo_buf[i]; i++;
- linep = linep + (text->undo_buf[i] << 8); i++;
- linep = linep + (text->undo_buf[i] << 16); i++;
- linep = linep + (text->undo_buf[i] << 24); i++;
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
printf("> (%d)", linep);
}
else if (op == UNDO_INDENT || op == UNDO_UNINDENT) {
i++;
- charp = text->undo_buf[i]; i++;
- charp = charp + (text->undo_buf[i] << 8); i++;
+ charp = utxt->buf[i]; i++;
+ charp = charp + (utxt->buf[i] << 8); i++;
- linep = text->undo_buf[i]; i++;
- linep = linep + (text->undo_buf[i] << 8); i++;
- linep = linep + (text->undo_buf[i] << 16); i++;
- linep = linep + (text->undo_buf[i] << 24); i++;
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
printf("to <%d, %d> ", linep, charp);
- charp = text->undo_buf[i]; i++;
- charp = charp + (text->undo_buf[i] << 8); i++;
+ charp = utxt->buf[i]; i++;
+ charp = charp + (utxt->buf[i] << 8); i++;
- linep = text->undo_buf[i]; i++;
- linep = linep + (text->undo_buf[i] << 8); i++;
- linep = linep + (text->undo_buf[i] << 16); i++;
- linep = linep + (text->undo_buf[i] << 24); i++;
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
printf("from <%d, %d>", linep, charp);
}
@@ -1688,113 +1673,113 @@ static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int va
}
/* store the cur cursor to the undo buffer (6 bytes)*/
-static void txt_undo_store_cur(Text *text)
+static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->curc);
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->curl));
+ txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl));
}
/* store the sel cursor to the undo buffer (6 bytes) */
-static void txt_undo_store_sel(Text *text)
+static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_uint16(text->undo_buf, &text->undo_pos, text->selc);
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, txt_get_span(text->lines.first, text->sell));
+ txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell));
}
/* store both cursors to the undo buffer (12 bytes) */
-static void txt_undo_store_cursors(Text *text)
+static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_cur(text);
- txt_undo_store_sel(text);
+ txt_undo_store_cur(text, utxt);
+ txt_undo_store_sel(text, utxt);
}
/* store an operator along with a block of data */
-static void txt_undo_add_blockop(Text *text, int op, const char *buf)
+static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf)
{
unsigned int length = strlen(buf);
- if (!max_undo_test(text, 2 + 12 + 4 + length + 4 + 1)) {
+ if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) {
return;
}
/* 2 bytes */
- text->undo_pos++;
- text->undo_buf[text->undo_pos] = op;
- text->undo_pos++;
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op;
+ utxt->pos++;
/* 12 bytes */
- txt_undo_store_cursors(text);
+ txt_undo_store_cursors(text, utxt);
/* 4 bytes */
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
/* 'length' bytes */
- strncpy(text->undo_buf + text->undo_pos, buf, length);
- text->undo_pos += length;
+ strncpy(utxt->buf + utxt->pos, buf, length);
+ utxt->pos += length;
/* 4 bytes */
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
/* 1 byte */
- text->undo_buf[text->undo_pos] = op;
+ utxt->buf[utxt->pos] = op;
- txt_undo_end(text);
+ txt_undo_end(text, utxt);
}
/* store a regular operator */
-void txt_undo_add_op(Text *text, int op)
+void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op)
{
- if (!max_undo_test(text, 2 + 12 + 1)) {
+ if (!max_undo_test(utxt, 2 + 12 + 1)) {
return;
}
/* 2 bytes */
- text->undo_pos++;
- text->undo_buf[text->undo_pos] = op;
- text->undo_pos++;
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op;
+ utxt->pos++;
/* 12 bytes */
- txt_undo_store_cursors(text);
+ txt_undo_store_cursors(text, utxt);
/* 1 byte */
- text->undo_buf[text->undo_pos] = op;
+ utxt->buf[utxt->pos] = op;
- txt_undo_end(text);
+ txt_undo_end(text, utxt);
}
/* store an operator for a single character */
-static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
+static void txt_undo_add_charop(Text *text, TextUndoBuf *utxt, int op_start, unsigned int c)
{
char utf8[BLI_UTF8_MAX];
size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
if (utf8_size < 4 && 0) {
- if (!max_undo_test(text, 2 + 6 + utf8_size + 1)) {
+ if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) {
return;
}
/* 2 bytes */
- text->undo_pos++;
- text->undo_buf[text->undo_pos] = op_start + utf8_size - 1;
- text->undo_pos++;
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op_start + utf8_size - 1;
+ utxt->pos++;
/* 6 bytes */
- txt_undo_store_cur(text);
+ txt_undo_store_cur(text, utxt);
/* 'utf8_size' bytes */
for (i = 0; i < utf8_size; i++) {
- text->undo_buf[text->undo_pos] = utf8[i];
- text->undo_pos++;
+ utxt->buf[utxt->pos] = utf8[i];
+ utxt->pos++;
}
/* 1 byte */
- text->undo_buf[text->undo_pos] = op_start + utf8_size - 1;
+ utxt->buf[utxt->pos] = op_start + utf8_size - 1;
}
else {
- if (!max_undo_test(text, 2 + 6 + 4 + 1)) {
+ if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) {
return;
}
/* 2 bytes */
- text->undo_pos++;
- text->undo_buf[text->undo_pos] = op_start + 3;
- text->undo_pos++;
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op_start + 3;
+ utxt->pos++;
/* 6 bytes */
- txt_undo_store_cur(text);
+ txt_undo_store_cur(text, utxt);
/* 4 bytes */
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, c);
/* 1 byte */
- text->undo_buf[text->undo_pos] = op_start + 3;
+ utxt->buf[utxt->pos] = op_start + 3;
}
- txt_undo_end(text);
+ txt_undo_end(text, utxt);
}
/* extends Link */
@@ -1808,7 +1793,7 @@ struct LinkInt {
* of the lines that should not be indented back.
*/
static void txt_undo_add_unprefix_op(
- Text *text, char undo_op,
+ Text *text, TextUndoBuf *utxt, char undo_op,
const ListBase *line_index_mask, const int line_index_mask_len)
{
struct LinkInt *idata;
@@ -1816,35 +1801,35 @@ static void txt_undo_add_unprefix_op(
BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
/* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
- if (!max_undo_test(text, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
+ if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
return;
}
/* 2 bytes */
- text->undo_pos++;
- text->undo_buf[text->undo_pos] = undo_op;
- text->undo_pos++;
+ utxt->pos++;
+ utxt->buf[utxt->pos] = undo_op;
+ utxt->pos++;
/* Adding number of line numbers to read
* 4 bytes */
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
/* Adding linenumbers of lines that shall not be indented if undoing.
* 'line_index_mask_len * 4' bytes */
for (idata = line_index_mask->first; idata; idata = idata->next) {
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value);
}
/* Adding number of line numbers to read again.
* 4 bytes */
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
/* Adding current selection.
* 12 bytes */
- txt_undo_store_cursors(text);
+ txt_undo_store_cursors(text, utxt);
/* Closing with OP (same as above).
* 1 byte */
- text->undo_buf[text->undo_pos] = undo_op;
+ utxt->buf[utxt->pos] = undo_op;
/* Marking as last undo operation */
- txt_undo_end(text);
+ txt_undo_end(text, utxt);
}
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
@@ -1999,9 +1984,9 @@ static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, s
return unicode;
}
-void txt_do_undo(Text *text)
+void txt_do_undo(Text *text, TextUndoBuf *utxt)
{
- int op = text->undo_buf[text->undo_pos];
+ int op = utxt->buf[utxt->pos];
int prev_flags;
unsigned int linep;
unsigned int uni_char;
@@ -2010,11 +1995,11 @@ void txt_do_undo(Text *text)
unsigned short charp;
char *buf;
- if (text->undo_pos < 0) {
+ if (utxt->pos < 0) {
return;
}
- text->undo_pos--;
+ utxt->pos--;
undoing = 1;
@@ -2023,16 +2008,16 @@ void txt_do_undo(Text *text)
case UNDO_INSERT_2:
case UNDO_INSERT_3:
case UNDO_INSERT_4:
- text->undo_pos -= op - UNDO_INSERT_1 + 1;
+ utxt->pos -= op - UNDO_INSERT_1 + 1;
/* get and restore the cursors */
- txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_delete_char(text);
+ txt_delete_char(text, utxt);
- text->undo_pos--;
+ utxt->pos--;
break;
case UNDO_BS_1:
@@ -2040,16 +2025,16 @@ void txt_do_undo(Text *text)
case UNDO_BS_3:
case UNDO_BS_4:
charp = op - UNDO_BS_1 + 1;
- uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
/* get and restore the cursors */
- txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uni_char);
+ txt_add_char(text, utxt, uni_char);
- text->undo_pos--;
+ utxt->pos--;
break;
case UNDO_DEL_1:
@@ -2057,50 +2042,50 @@ void txt_do_undo(Text *text)
case UNDO_DEL_3:
case UNDO_DEL_4:
charp = op - UNDO_DEL_1 + 1;
- uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
/* get and restore the cursors */
- txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uni_char);
+ txt_add_char(text, utxt, uni_char);
txt_move_left(text, 0);
- text->undo_pos--;
+ utxt->pos--;
break;
case UNDO_DBLOCK:
{
int i;
/* length of the string in the buffer */
- linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
buf = MEM_mallocN(linep + 1, "dblock buffer");
for (i = 0; i < linep; i++) {
- buf[(linep - 1) - i] = text->undo_buf[text->undo_pos];
- text->undo_pos--;
+ buf[(linep - 1) - i] = utxt->buf[utxt->pos];
+ utxt->pos--;
}
buf[i] = 0;
/* skip over the length that was stored again */
- text->undo_pos -= 4;
+ utxt->pos -= 4;
/* Get the cursor positions */
- txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
/* move cur to location that needs buff inserted */
txt_move_to(text, curln, curc, 0);
- txt_insert_buf(text, buf);
+ txt_insert_buf(text, utxt, buf);
MEM_freeN(buf);
/* restore the cursors */
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
- text->undo_pos--;
+ utxt->pos--;
break;
}
@@ -2108,23 +2093,23 @@ void txt_do_undo(Text *text)
{
int i;
/* length of the string in the buffer */
- linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
/* txt_backspace_char removes utf8-characters, not bytes */
buf = MEM_mallocN(linep + 1, "iblock buffer");
for (i = 0; i < linep; i++) {
- buf[(linep - 1) - i] = text->undo_buf[text->undo_pos];
- text->undo_pos--;
+ buf[(linep - 1) - i] = utxt->buf[utxt->pos];
+ utxt->pos--;
}
buf[i] = 0;
linep = BLI_strlen_utf8(buf);
MEM_freeN(buf);
/* skip over the length that was stored again */
- text->undo_pos -= 4;
+ utxt->pos -= 4;
/* get and restore the cursors */
- txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
@@ -2140,9 +2125,9 @@ void txt_do_undo(Text *text)
text->flags = prev_flags;
}
- txt_delete_selected(text);
+ txt_delete_selected(text, utxt);
- text->undo_pos--;
+ utxt->pos--;
break;
}
case UNDO_INDENT:
@@ -2151,37 +2136,37 @@ void txt_do_undo(Text *text)
case UNDO_MOVE_LINES_UP:
case UNDO_MOVE_LINES_DOWN:
/* get and restore the cursors */
- txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
if (op == UNDO_INDENT) {
- txt_unindent(text);
+ txt_unindent(text, utxt);
}
else if (op == UNDO_COMMENT) {
- txt_uncomment(text);
+ txt_uncomment(text, utxt);
}
else if (op == UNDO_DUPLICATE) {
txt_delete_line(text, text->curl->next);
}
else if (op == UNDO_MOVE_LINES_UP) {
- txt_move_lines(text, TXT_MOVE_LINE_DOWN);
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
}
else if (op == UNDO_MOVE_LINES_DOWN) {
- txt_move_lines(text, TXT_MOVE_LINE_UP);
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
}
- text->undo_pos--;
+ utxt->pos--;
break;
case UNDO_UNINDENT:
case UNDO_UNCOMMENT:
{
- void (*txt_prefix_fn)(Text *);
- void (*txt_unprefix_fn)(Text *);
+ void (*txt_prefix_fn)(Text *, TextUndoBuf *);
+ void (*txt_unprefix_fn)(Text *, TextUndoBuf *);
int count;
int i;
/* Get and restore the cursors */
- txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
@@ -2195,30 +2180,30 @@ void txt_do_undo(Text *text)
txt_unprefix_fn = txt_uncomment;
}
- txt_prefix_fn(text);
+ txt_prefix_fn(text, utxt);
/* Get the count */
- count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ count = txt_undo_read_uint32(utxt->buf, &utxt->pos);
/* Iterate! */
txt_pop_sel(text);
for (i = 0; i < count; i++) {
- txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0);
+ txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0);
/* Un-un-unindent/comment */
- txt_unprefix_fn(text);
+ txt_unprefix_fn(text, utxt);
}
/* Restore selection */
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
/* Jumo over count */
- txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ txt_undo_read_uint32(utxt->buf, &utxt->pos);
/* Jump over closing OP byte */
- text->undo_pos--;
+ utxt->pos--;
break;
}
default:
//XXX error("Undo buffer error - resetting");
- text->undo_pos = -1;
+ utxt->pos = -1;
break;
}
@@ -2226,7 +2211,7 @@ void txt_do_undo(Text *text)
undoing = 0;
}
-void txt_do_redo(Text *text)
+void txt_do_redo(Text *text, TextUndoBuf *utxt)
{
char op;
char *buf;
@@ -2236,11 +2221,11 @@ void txt_do_redo(Text *text)
unsigned int curln, selln;
unsigned short curc, selc;
- text->undo_pos++;
- op = text->undo_buf[text->undo_pos];
+ utxt->pos++;
+ op = utxt->buf[utxt->pos];
if (!op) {
- text->undo_pos--;
+ utxt->pos--;
return;
}
@@ -2251,35 +2236,35 @@ void txt_do_redo(Text *text)
case UNDO_INSERT_2:
case UNDO_INSERT_3:
case UNDO_INSERT_4:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
charp = op - UNDO_INSERT_1 + 1;
- uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp);
- txt_add_char(text, uni_uchar);
+ txt_add_char(text, utxt, uni_uchar);
break;
case UNDO_BS_1:
case UNDO_BS_2:
case UNDO_BS_3:
case UNDO_BS_4:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- text->undo_pos += op - UNDO_BS_1 + 1;
+ utxt->pos += op - UNDO_BS_1 + 1;
/* move right so we backspace the correct char */
txt_move_right(text, 0);
- txt_backspace_char(text);
+ txt_backspace_char(text, utxt);
break;
@@ -2287,60 +2272,60 @@ void txt_do_redo(Text *text)
case UNDO_DEL_2:
case UNDO_DEL_3:
case UNDO_DEL_4:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- text->undo_pos += op - UNDO_DEL_1 + 1;
+ utxt->pos += op - UNDO_DEL_1 + 1;
- txt_delete_char(text);
+ txt_delete_char(text, utxt);
break;
case UNDO_DBLOCK:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
/* length of the block */
- linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
- text->undo_pos += linep;
+ utxt->pos += linep;
/* skip over the length that was stored again */
- text->undo_pos += 4;
+ utxt->pos += 4;
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
break;
case UNDO_IBLOCK:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
/* length of the block */
- linep = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
buf = MEM_mallocN(linep + 1, "iblock buffer");
- memcpy(buf, &text->undo_buf[text->undo_pos], linep);
- text->undo_pos += linep;
+ memcpy(buf, &utxt->buf[utxt->pos], linep);
+ utxt->pos += linep;
buf[linep] = 0;
- txt_insert_buf(text, buf);
+ txt_insert_buf(text, utxt, buf);
MEM_freeN(buf);
/* skip over the length that was stored again */
- text->undo_pos += 4;
+ utxt->pos += 4;
break;
@@ -2350,38 +2335,38 @@ void txt_do_redo(Text *text)
case UNDO_DUPLICATE:
case UNDO_MOVE_LINES_UP:
case UNDO_MOVE_LINES_DOWN:
- text->undo_pos++;
+ utxt->pos++;
/* get and restore the cursors */
- txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
if (op == UNDO_INDENT) {
- txt_indent(text);
+ txt_indent(text, utxt);
}
else if (op == UNDO_COMMENT) {
- txt_comment(text);
+ txt_comment(text, utxt);
}
else if (op == UNDO_UNCOMMENT) {
- txt_uncomment(text);
+ txt_uncomment(text, utxt);
}
else if (op == UNDO_DUPLICATE) {
- txt_duplicate_line(text);
+ txt_duplicate_line(text, utxt);
}
else if (op == UNDO_MOVE_LINES_UP) {
/* offset the cursor by + 1 */
txt_move_to(text, curln + 1, curc, 0);
txt_move_to(text, selln + 1, selc, 1);
- txt_move_lines(text, TXT_MOVE_LINE_UP);
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
}
else if (op == UNDO_MOVE_LINES_DOWN) {
/* offset the cursor by - 1 */
txt_move_to(text, curln - 1, curc, 0);
txt_move_to(text, selln - 1, selc, 1);
- txt_move_lines(text, TXT_MOVE_LINE_DOWN);
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
}
/* re-restore the cursors since they got moved when redoing */
@@ -2394,24 +2379,24 @@ void txt_do_redo(Text *text)
int count;
int i;
- text->undo_pos++;
+ utxt->pos++;
/* Scan all the stuff described in txt_undo_add_unindent_op */
- count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ count = txt_redo_read_uint32(utxt->buf, &utxt->pos);
for (i = 0; i < count; i++) {
- txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ txt_redo_read_uint32(utxt->buf, &utxt->pos);
}
/* Count again */
- txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ txt_redo_read_uint32(utxt->buf, &utxt->pos);
/* Get the selection and re-unindent */
- txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, selln, selc, 1);
- txt_unindent(text);
+ txt_unindent(text, utxt);
break;
}
default:
//XXX error("Undo buffer error - resetting");
- text->undo_pos = -1;
+ utxt->pos = -1;
break;
}
@@ -2423,16 +2408,16 @@ void txt_do_redo(Text *text)
/* Line editing functions */
/**************************/
-void txt_split_curline(Text *text)
+void txt_split_curline(Text *text, TextUndoBuf *utxt)
{
TextLine *ins;
char *left, *right;
if (!text->curl) return;
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
- if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
+ if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n');
/* Make the two half strings */
@@ -2504,7 +2489,7 @@ static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
txt_clean_text(text);
}
-void txt_duplicate_line(Text *text)
+void txt_duplicate_line(Text *text, TextUndoBuf *utxt)
{
TextLine *textline;
@@ -2517,18 +2502,18 @@ void txt_duplicate_line(Text *text)
txt_make_dirty(text);
txt_clean_text(text);
- if (!undoing) txt_undo_add_op(text, UNDO_DUPLICATE);
+ if (!undoing) txt_undo_add_op(text, utxt, UNDO_DUPLICATE);
}
}
-void txt_delete_char(Text *text)
+void txt_delete_char(Text *text, TextUndoBuf *utxt)
{
unsigned int c = '\n';
if (!text->curl) return;
if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
txt_make_dirty(text);
return;
}
@@ -2554,24 +2539,24 @@ void txt_delete_char(Text *text)
txt_make_dirty(text);
txt_clean_text(text);
- if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c);
+ if (!undoing) txt_undo_add_charop(text, utxt, UNDO_DEL_1, c);
}
-void txt_delete_word(Text *text)
+void txt_delete_word(Text *text, TextUndoBuf *utxt)
{
txt_jump_right(text, true, true);
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
txt_make_dirty(text);
}
-void txt_backspace_char(Text *text)
+void txt_backspace_char(Text *text, TextUndoBuf *utxt)
{
unsigned int c = '\n';
if (!text->curl) return;
if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
txt_make_dirty(text);
return;
}
@@ -2603,13 +2588,13 @@ void txt_backspace_char(Text *text)
txt_make_dirty(text);
txt_clean_text(text);
- if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c);
+ if (!undoing) txt_undo_add_charop(text, utxt, UNDO_BS_1, c);
}
-void txt_backspace_word(Text *text)
+void txt_backspace_word(Text *text, TextUndoBuf *utxt)
{
txt_jump_left(text, true, true);
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
txt_make_dirty(text);
}
@@ -2618,17 +2603,17 @@ void txt_backspace_word(Text *text)
* Remember to change this string according to max tab size */
static char tab_to_spaces[] = " ";
-static void txt_convert_tab_to_spaces(Text *text)
+static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt)
{
/* sb aims to pad adjust the tab-width needed so that the right number of spaces
* is added so that the indention of the line is the right width (i.e. aligned
* to multiples of TXT_TABSIZE)
*/
const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
- txt_insert_buf(text, sb);
+ txt_insert_buf(text, utxt, sb);
}
-static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
+static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs)
{
char *tmp, ch[BLI_UTF8_MAX];
size_t add_len;
@@ -2636,19 +2621,19 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
if (!text->curl) return 0;
if (add == '\n') {
- txt_split_curline(text);
+ txt_split_curline(text, utxt);
return true;
}
/* insert spaces rather than tabs */
if (add == '\t' && replace_tabs) {
- txt_convert_tab_to_spaces(text);
+ txt_convert_tab_to_spaces(text, utxt);
return true;
}
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
- if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add);
+ if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
add_len = BLI_str_utf8_from_unicode(add, ch);
@@ -2670,23 +2655,23 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
return 1;
}
-bool txt_add_char(Text *text, unsigned int add)
+bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
- return txt_add_char_intern(text, add, (text->flags & TXT_TABSTOSPACES) != 0);
+ return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0);
}
-bool txt_add_raw_char(Text *text, unsigned int add)
+bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
- return txt_add_char_intern(text, add, 0);
+ return txt_add_char_intern(text, utxt, add, 0);
}
-void txt_delete_selected(Text *text)
+void txt_delete_selected(Text *text, TextUndoBuf *utxt)
{
- txt_delete_sel(text);
+ txt_delete_sel(text, utxt);
txt_make_dirty(text);
}
-bool txt_replace_char(Text *text, unsigned int add)
+bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
unsigned int del;
size_t del_size = 0, add_size;
@@ -2696,7 +2681,7 @@ bool txt_replace_char(Text *text, unsigned int add)
/* If text is selected or we're at the end of the line just use txt_add_char */
if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
- return txt_add_char(text, add);
+ return txt_add_char(text, utxt, add);
}
del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
@@ -2724,10 +2709,10 @@ bool txt_replace_char(Text *text, unsigned int add)
/* Should probably create a new op for this */
if (!undoing) {
- txt_undo_add_charop(text, UNDO_INSERT_1, add);
+ txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
text->curc -= add_size;
txt_pop_sel(text);
- txt_undo_add_charop(text, UNDO_DEL_1, del);
+ txt_undo_add_charop(text, utxt, UNDO_DEL_1, del);
text->curc += add_size;
txt_pop_sel(text);
}
@@ -2867,7 +2852,7 @@ static void txt_select_unprefix(
/* caller must handle undo */
}
-void txt_comment(Text *text)
+void txt_comment(Text *text, TextUndoBuf *utxt)
{
const char *prefix = "#";
@@ -2878,11 +2863,11 @@ void txt_comment(Text *text)
txt_select_prefix(text, prefix);
if (!undoing) {
- txt_undo_add_op(text, UNDO_COMMENT);
+ txt_undo_add_op(text, utxt, UNDO_COMMENT);
}
}
-void txt_uncomment(Text *text)
+void txt_uncomment(Text *text, TextUndoBuf *utxt)
{
const char *prefix = "#";
ListBase line_index_mask;
@@ -2895,13 +2880,13 @@ void txt_uncomment(Text *text)
txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
if (!undoing) {
- txt_undo_add_unprefix_op(text, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
+ txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
}
BLI_freelistN(&line_index_mask);
}
-void txt_indent(Text *text)
+void txt_indent(Text *text, TextUndoBuf *utxt)
{
const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
@@ -2912,11 +2897,11 @@ void txt_indent(Text *text)
txt_select_prefix(text, prefix);
if (!undoing) {
- txt_undo_add_op(text, UNDO_INDENT);
+ txt_undo_add_op(text, utxt, UNDO_INDENT);
}
}
-void txt_unindent(Text *text)
+void txt_unindent(Text *text, TextUndoBuf *utxt)
{
const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
ListBase line_index_mask;
@@ -2929,13 +2914,13 @@ void txt_unindent(Text *text)
txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
if (!undoing) {
- txt_undo_add_unprefix_op(text, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
+ txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
}
BLI_freelistN(&line_index_mask);
}
-void txt_move_lines(struct Text *text, const int direction)
+void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction)
{
TextLine *line_other;
@@ -2962,7 +2947,7 @@ void txt_move_lines(struct Text *text, const int direction)
txt_clean_text(text);
if (!undoing) {
- txt_undo_add_op(text, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
+ txt_undo_add_op(text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
}
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 0e2ac811a41..250408642bb 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -55,7 +55,6 @@
#include "IMB_imbuf.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_colorband.h"
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
new file mode 100644
index 00000000000..760c6a60976
--- /dev/null
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -0,0 +1,831 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/undo_system.c
+ * \ingroup bke
+ *
+ * Used by ED_undo.h, internal implementation.
+ */
+
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_sys_types.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_sort_utils.h"
+
+#include "DNA_listBase.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
+
+#include "MEM_guardedalloc.h"
+
+#define undo_stack _wm_undo_stack_disallow /* pass in as a variable always. */
+
+/** Odd requirement of Blender that we always keep a memfile undo in the stack. */
+#define WITH_GLOBAL_UNDO_KEEP_ONE
+
+/** Make sure all ID's created at the point we add an undo step that uses ID's. */
+#define WITH_GLOBAL_UNDO_ENSURE_UPDATED
+
+/** We only need this locally. */
+static CLG_LogRef LOG = {"bke.undosys"};
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Nested Undo Checks
+ *
+ * Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks.
+ * bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious.
+ * Best we have a check which shows the problem immediately.
+ *
+ * \{ */
+#define WITH_NESTED_UNDO_CHECK
+
+#ifdef WITH_NESTED_UNDO_CHECK
+static bool g_undo_callback_running = false;
+# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state)
+# define UNDO_NESTED_CHECK_BEGIN { \
+ UNDO_NESTED_ASSERT(false); \
+ g_undo_callback_running = true; \
+} ((void)0)
+# define UNDO_NESTED_CHECK_END { \
+ UNDO_NESTED_ASSERT(true); \
+ g_undo_callback_running = false; \
+} ((void)0)
+#else
+# define UNDO_NESTED_ASSERT(state) ((void)0)
+# define UNDO_NESTED_CHECK_BEGIN ((void)0)
+# define UNDO_NESTED_CHECK_END ((void)0)
+#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Undo Types
+ *
+ * Unfortunately we need this for a handful of places.
+ */
+const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
+/** \} */
+
+/* UndoType */
+
+static ListBase g_undo_types = {NULL, NULL};
+
+static const UndoType *BKE_undosys_type_from_context(bContext *C)
+{
+ for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) {
+ /* No poll means we don't check context. */
+ if (ut->poll && ut->poll(C)) {
+ return ut;
+ }
+ }
+ return NULL;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Callback Wrappers
+ *
+ * #UndoRefID is simply a way to avoid inlining name copy and lookups,
+ * since it's easy to forget a single case when done inline (crashing in some cases).
+ *
+ * \{ */
+
+static void undosys_id_ref_store(void *UNUSED(user_data), UndoRefID *id_ref)
+{
+ BLI_assert(id_ref->name[0] == '\0');
+ if (id_ref->ptr) {
+ BLI_strncpy(id_ref->name, id_ref->ptr->name, sizeof(id_ref->name));
+ /* Not needed, just prevents stale data access. */
+ id_ref->ptr = NULL;
+ }
+}
+
+static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
+{
+ /* Note: we could optimize this, for now it's not too bad since it only runs when we access undo! */
+ Main *bmain = user_data;
+ ListBase *lb = which_libbase(bmain, GS(id_ref->name));
+ for (ID *id = lb->first; id; id = id->next) {
+ if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) {
+ id_ref->ptr = id;
+ break;
+ }
+ }
+}
+
+static bool undosys_step_encode(bContext *C, UndoStep *us)
+{
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ UNDO_NESTED_CHECK_BEGIN;
+ bool ok = us->type->step_encode(C, us);
+ UNDO_NESTED_CHECK_END;
+ if (ok) {
+ if (us->type->step_foreach_ID_ref != NULL) {
+ /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
+ Main *bmain = G.main;
+ us->type->step_foreach_ID_ref(us, undosys_id_ref_store, bmain);
+ }
+ }
+ if (ok == false) {
+ CLOG_INFO(&LOG, 2, "encode callback didn't create undo step");
+ }
+ return ok;
+}
+
+static void undosys_step_decode(bContext *C, UndoStep *us, int dir)
+{
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ if (us->type->step_foreach_ID_ref) {
+ /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
+ Main *bmain = G.main;
+ us->type->step_foreach_ID_ref(us, undosys_id_ref_resolve, bmain);
+ }
+
+ UNDO_NESTED_CHECK_BEGIN;
+ us->type->step_decode(C, us, dir);
+ UNDO_NESTED_CHECK_END;
+}
+
+static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us)
+{
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ UNDO_NESTED_CHECK_BEGIN;
+ us->type->step_free(us);
+ UNDO_NESTED_CHECK_END;
+
+ BLI_remlink(&ustack->steps, us);
+ MEM_freeN(us);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo Stack
+ * \{ */
+
+#ifndef NDEBUG
+static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty)
+{
+ if (ustack->step_active != NULL) {
+ BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
+ BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
+ }
+ if (expect_non_empty) {
+ BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
+ }
+}
+#else
+static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty)
+{
+ UNUSED_VARS(ustack, expect_non_empty);
+}
+#endif
+
+UndoStack *BKE_undosys_stack_create(void)
+{
+ UndoStack *ustack = MEM_callocN(sizeof(UndoStack), __func__);
+ return ustack;
+}
+
+void BKE_undosys_stack_destroy(UndoStack *ustack)
+{
+ BKE_undosys_stack_clear(ustack);
+ MEM_freeN(ustack);
+}
+
+void BKE_undosys_stack_clear(UndoStack *ustack)
+{
+ UNDO_NESTED_ASSERT(false);
+ CLOG_INFO(&LOG, 1, "steps=%d", BLI_listbase_count(&ustack->steps));
+ for (UndoStep *us = ustack->steps.last, *us_prev; us; us = us_prev) {
+ us_prev = us->prev;
+ undosys_step_free_and_unlink(ustack, us);
+ }
+ BLI_listbase_clear(&ustack->steps);
+ ustack->step_active = NULL;
+}
+
+static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct Main *bmain)
+{
+ UNDO_NESTED_ASSERT(false);
+ CLOG_INFO(&LOG, 1, "'%s'", name);
+ bContext *C_temp = CTX_create();
+ CTX_data_main_set(C_temp, bmain);
+ bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
+ CTX_free(C_temp);
+ return ok;
+}
+
+void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
+{
+ UNDO_NESTED_ASSERT(false);
+ undosys_stack_push_main(ustack, "original", bmain);
+}
+
+/* name optional */
+bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name)
+{
+ if (name) {
+ UndoStep *us = BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
+ return us && us->prev;
+ }
+
+ return !BLI_listbase_is_empty(&ustack->steps);
+}
+
+UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut)
+{
+ UndoStep *us = ustack->step_active;
+ while (us && (us->type != ut)) {
+ us = us->prev;
+ }
+ return us;
+}
+
+UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
+{
+ UNDO_NESTED_ASSERT(false);
+ CLOG_INFO(&LOG, 1, "type='%s'", ut->name);
+ if (ustack->step_init && (ustack->step_init->type == ut)) {
+ return ustack->step_init;
+ }
+ return BKE_undosys_stack_active_with_type(ustack, ut);
+}
+
+/**
+ * \param steps: Limit the number of undo steps.
+ * \param memory_limit: Limit the amount of memory used by the undo stack.
+ */
+void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
+{
+ UNDO_NESTED_ASSERT(false);
+ if (!(steps || memory_limit)) {
+ return;
+ }
+
+ CLOG_INFO(&LOG, 1, "steps=%d, memory_limit=%zu", steps, memory_limit);
+ UndoStep *us;
+#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
+ UndoStep *us_exclude = NULL;
+#endif
+ /* keep at least two (original + other) */
+ size_t data_size_all = 0;
+ size_t us_count = 0;
+ for (us = ustack->steps.last; us && us->prev; us = us->prev) {
+ if (memory_limit) {
+ data_size_all += us->data_size;
+ if (data_size_all > memory_limit) {
+ break;
+ }
+ }
+ if (steps) {
+ if (us_count == steps) {
+ break;
+ }
+ if (us->skip == false) {
+ us_count += 1;
+ }
+ }
+ }
+
+ if (us) {
+ if (us->prev && us->prev->prev) {
+ us = us->prev;
+ }
+
+#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
+ /* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */
+ if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ us_exclude = us->prev;
+ while (us_exclude && us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ us_exclude = us_exclude->prev;
+ }
+ if (us_exclude) {
+ BLI_remlink(&ustack->steps, us_exclude);
+ }
+ }
+#endif
+ /* Free from first to last, free functions may update de-duplication info (see #MemFileUndoStep). */
+ while (ustack->steps.first != us) {
+ UndoStep *us_first = ustack->steps.first;
+ BLI_assert(us_first != ustack->step_active);
+ undosys_step_free_and_unlink(ustack, us_first);
+ }
+
+#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
+ if (us_exclude) {
+ BLI_addhead(&ustack->steps, us_exclude);
+ }
+#endif
+ }
+}
+
+/** \} */
+
+UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
+{
+ UNDO_NESTED_ASSERT(false);
+ /* We could detect and clean this up (but it should never happen!). */
+ BLI_assert(ustack->step_init == NULL);
+ if (ut->step_encode_init) {
+ undosys_stack_validate(ustack, false);
+ UndoStep *us = MEM_callocN(ut->step_size, __func__);
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name);
+ if (name != NULL) {
+ BLI_strncpy(us->name, name, sizeof(us->name));
+ }
+ us->type = ut;
+ ustack->step_init = us;
+ ut->step_encode_init(C, us);
+ undosys_stack_validate(ustack, true);
+ return us;
+ }
+ else {
+ return NULL;
+ }
+}
+
+UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name)
+{
+ UNDO_NESTED_ASSERT(false);
+ /* We could detect and clean this up (but it should never happen!). */
+ BLI_assert(ustack->step_init == NULL);
+ const UndoType *ut = BKE_undosys_type_from_context(C);
+ if (ut == NULL) {
+ return NULL;
+ }
+ return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
+}
+
+bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
+{
+ UNDO_NESTED_ASSERT(false);
+ undosys_stack_validate(ustack, false);
+ bool is_not_empty = ustack->step_active != NULL;
+
+ /* Remove all undos after (also when 'ustack->step_active == NULL'). */
+ while (ustack->steps.last != ustack->step_active) {
+ UndoStep *us_iter = ustack->steps.last;
+ undosys_step_free_and_unlink(ustack, us_iter);
+ undosys_stack_validate(ustack, is_not_empty);
+ }
+
+ if (ustack->step_active) {
+ BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
+ }
+
+#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED
+ if (ut->step_foreach_ID_ref != NULL) {
+ Main *bmain = G.main;
+ if (bmain->is_memfile_undo_written == false) {
+ const char *name_internal = "MemFile Internal";
+ if (undosys_stack_push_main(ustack, name_internal, bmain)) {
+ UndoStep *us = ustack->steps.last;
+ BLI_assert(STREQ(us->name, name_internal));
+ us->skip = true;
+ }
+ }
+ }
+#endif
+
+ UndoStep *us = ustack->step_init ? ustack->step_init : MEM_callocN(ut->step_size, __func__);
+ ustack->step_init = NULL;
+ if (us->name[0] == '\0') {
+ BLI_strncpy(us->name, name, sizeof(us->name));
+ }
+ us->type = ut;
+ /* initialized, not added yet. */
+
+ if (undosys_step_encode(C, us)) {
+ ustack->step_active = us;
+ BLI_addtail(&ustack->steps, us);
+ undosys_stack_validate(ustack, true);
+ return true;
+ }
+ else {
+ MEM_freeN(us);
+ undosys_stack_validate(ustack, true);
+ return false;
+ }
+}
+
+bool BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
+{
+ UNDO_NESTED_ASSERT(false);
+ const UndoType *ut = ustack->step_init ? ustack->step_init->type : BKE_undosys_type_from_context(C);
+ if (ut == NULL) {
+ return false;
+ }
+ return BKE_undosys_step_push_with_type(ustack, C, name, ut);
+}
+
+
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
+UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
+{
+ if (us) {
+ const UndoType *ut = us->type;
+ while ((us = us->next)) {
+ if (us->type == ut) {
+ return us;
+ }
+ }
+
+ }
+ return us;
+}
+
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
+UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us)
+{
+ if (us) {
+ const UndoType *ut = us->type;
+ while ((us = us->prev)) {
+ if (us->type == ut) {
+ return us;
+ }
+ }
+
+ }
+ return us;
+}
+
+UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut)
+{
+ for (UndoStep *us = ustack->steps.last; us; us = us->prev) {
+ if (us->type == ut) {
+ if (STREQ(name, us->name)) {
+ return us;
+ }
+ }
+ }
+ return NULL;
+}
+
+UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name)
+{
+ return BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
+}
+
+bool BKE_undosys_step_undo_with_data_ex(
+ UndoStack *ustack, bContext *C, UndoStep *us,
+ bool use_skip)
+{
+ UNDO_NESTED_ASSERT(false);
+ if (us) {
+ undosys_stack_validate(ustack, true);
+ }
+ UndoStep *us_prev = us ? us->prev : NULL;
+ if (us && us->type->mode == BKE_UNDOTYPE_MODE_STORE) {
+ /* The current state is a copy, we need to load the previous state. */
+ us = us_prev;
+ }
+
+ if (us != NULL) {
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ undosys_step_decode(C, us, -1);
+ ustack->step_active = us_prev;
+ undosys_stack_validate(ustack, true);
+ if (use_skip) {
+ if (ustack->step_active && ustack->step_active->skip) {
+ CLOG_INFO(&LOG, 2, "undo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
+ BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us)
+{
+ return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true);
+}
+
+bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
+{
+ return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
+}
+
+void BKE_undosys_step_undo_from_index(UndoStack *ustack, bContext *C, int index)
+{
+ UndoStep *us = BLI_findlink(&ustack->steps, index);
+ BLI_assert(us->skip == false);
+ BKE_undosys_step_load_data(ustack, C, us);
+}
+
+bool BKE_undosys_step_redo_with_data_ex(
+ UndoStack *ustack, bContext *C, UndoStep *us,
+ bool use_skip)
+{
+ UNDO_NESTED_ASSERT(false);
+ UndoStep *us_next = us ? us->next : NULL;
+ /* Unlike undo accumulate, we always use the next. */
+ us = us_next;
+
+ if (us != NULL) {
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ undosys_step_decode(C, us, 1);
+ ustack->step_active = us_next;
+ if (use_skip) {
+ if (ustack->step_active && ustack->step_active->skip) {
+ CLOG_INFO(&LOG, 2, "redo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
+ BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us)
+{
+ return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true);
+}
+
+bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
+{
+ return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
+}
+
+bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us)
+{
+ UNDO_NESTED_ASSERT(false);
+ const int index_active = BLI_findindex(&ustack->steps, ustack->step_active);
+ const int index_target = BLI_findindex(&ustack->steps, us);
+ BLI_assert(!ELEM(-1, index_active, index_target));
+ bool ok = true;
+
+ if (index_target < index_active) {
+ uint i = index_active - index_target;
+ while (i-- && ok) {
+ ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false);
+ }
+ }
+ else if (index_target > index_active) {
+ uint i = index_target - index_active;
+ while (i-- && ok) {
+ ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false);
+ }
+ }
+
+ if (ok) {
+ BLI_assert(ustack->step_active == us);
+ }
+
+ return ok;
+}
+
+bool BKE_undosys_step_undo_compat_only(UndoStack *ustack, bContext *C, int step)
+{
+ if (step == 0) {
+ return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
+ }
+ else if (step == 1) {
+ return BKE_undosys_step_undo(ustack, C);
+ }
+ else {
+ return BKE_undosys_step_redo(ustack, C);
+ }
+}
+/**
+ * Similar to #WM_operatortype_append
+ */
+UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *))
+{
+ UndoType *ut;
+
+ ut = MEM_callocN(sizeof(UndoType), __func__);
+
+ undosys_fn(ut);
+
+ BLI_assert(ut->mode != 0);
+
+ BLI_addtail(&g_undo_types, ut);
+
+ return ut;
+}
+
+void BKE_undosys_type_free_all(void)
+{
+ UndoType *ut;
+ while ((ut = BLI_pophead(&g_undo_types))) {
+ MEM_freeN(ut);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Reference Utilities
+ *
+ * Unfortunately we need this for a handful of places.
+ */
+
+static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(
+ UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data))
+{
+ for (UndoStep *us = ustack->steps.first; us; us = us->next) {
+ const UndoType *ut = us->type;
+ if (ut->step_foreach_ID_ref != NULL) {
+ ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data);
+ }
+ }
+}
+
+typedef struct UndoIDPtrMapItem {
+ /** Never changes (matches undo data). Use as sort key for binary search. */
+ const void *ptr;
+ /** Write the new pointers here. */
+ uint index;
+} UndoIDPtrMapItem;
+
+typedef struct UndoIDPtrMap {
+ UndoRefID *refs;
+ /**
+ * Pointer map, update 'dst' members before use.
+ * This is always sorted (adds some overhead when adding, in practice it's acceptable since).
+ */
+ UndoIDPtrMapItem *pmap;
+
+ /** Length for both 'refs' & 'pmap' */
+ uint len;
+ uint len_alloc;
+} UndoIDPtrMap;
+
+#ifdef DEBUG
+# define PMAP_DEFAULT_ALLOC 1
+#else
+# define PMAP_DEFAULT_ALLOC 32
+#endif
+
+void BKE_undosys_ID_map_foreach_ID_ref(
+ UndoIDPtrMap *map,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ for (uint i = 0; i < map->len; i++) {
+ foreach_ID_ref_fn(user_data, &map->refs[i]);
+ }
+}
+
+/**
+ * Return true when found, otherwise index is set to the index we should insert.
+ */
+static bool undosys_ID_map_lookup_index(const UndoIDPtrMap *map, const void *key, uint *r_index)
+{
+ const UndoIDPtrMapItem *pmap = map->pmap;
+ const uint len = map->len;
+ if (len == 0) {
+ if (*r_index) {
+ *r_index = 0;
+ }
+ return false;
+ }
+ int min = 0, max = len - 1;
+ while (min <= max) {
+ const uint mid = (min + max) / 2;
+ if (pmap[mid].ptr < key) {
+ min = mid + 1;
+ }
+ else if (pmap[mid].ptr == key) {
+ if (r_index) {
+ *r_index = mid;
+ }
+ return true;
+ }
+ else if (pmap[mid].ptr > key) {
+ max = mid - 1;
+ }
+ }
+ if (r_index) {
+ *r_index = min;
+ }
+ return false;
+}
+
+/**
+ * A set of ID's use for efficient decoding, so we can map pointers back to the newly loaded data
+ * without performing full look ups each time.
+ *
+ * This can be used as an old_pointer -> new_pointer lookup.
+ */
+UndoIDPtrMap *BKE_undosys_ID_map_create(void)
+{
+ UndoIDPtrMap *map = MEM_mallocN(sizeof(*map), __func__);
+ map->len_alloc = PMAP_DEFAULT_ALLOC;
+ map->refs = MEM_mallocN(sizeof(*map->refs) * map->len_alloc, __func__);
+ map->pmap = MEM_mallocN(sizeof(*map->pmap) * map->len_alloc, __func__);
+ map->len = 0;
+ return map;
+}
+void BKE_undosys_ID_map_destroy(UndoIDPtrMap *idpmap)
+{
+ MEM_SAFE_FREE(idpmap->refs);
+ MEM_SAFE_FREE(idpmap->pmap);
+ MEM_freeN(idpmap);
+}
+
+void BKE_undosys_ID_map_add(UndoIDPtrMap *map, ID *id)
+{
+ uint index;
+ if (id->lib != NULL) {
+ return;
+ }
+
+ if (undosys_ID_map_lookup_index(map, id, &index)) {
+ return; /* exists. */
+ }
+
+ const uint len_src = map->len;
+ const uint len_dst = map->len + 1;
+ if (len_dst > map->len_alloc) {
+ map->len_alloc *= 2;
+ BLI_assert(map->len_alloc >= len_dst);
+ map->pmap = MEM_reallocN(map->pmap, sizeof(*map->pmap) * map->len_alloc);
+ map->refs = MEM_reallocN(map->refs, sizeof(*map->refs) * map->len_alloc);
+ }
+
+#if 0 /* Will be done automatically in callback. */
+ BLI_strncpy(map->refs[len_src].name, id->name, sizeof(id->name));
+#else
+ map->refs[len_src].name[0] = '\0';
+#endif
+ map->refs[len_src].ptr = id;
+
+ if (len_src != 0 && index != len_src) {
+ memmove(&map->pmap[index + 1], &map->pmap[index], sizeof(*map->pmap) * (len_src - index));
+ }
+ map->pmap[index].ptr = id;
+ map->pmap[index].index = len_src;
+
+ map->len = len_dst;
+}
+
+ID *BKE_undosys_ID_map_lookup(const UndoIDPtrMap *map, const ID *id_src)
+{
+ /* We should only ever lookup indices which exist! */
+ uint index;
+ if (!undosys_ID_map_lookup_index(map, id_src, &index)) {
+ BLI_assert(0);
+ }
+ index = map->pmap[index].index;
+ ID *id_dst = map->refs[index].ptr;
+ BLI_assert(id_dst != NULL);
+ BLI_assert(STREQ(id_dst->name, map->refs[index].name));
+ return id_dst;
+}
+
+void BKE_undosys_ID_map_add_with_prev(UndoIDPtrMap *map, ID *id, ID **id_prev)
+{
+ if (id == *id_prev) {
+ return;
+ }
+ *id_prev = id;
+ BKE_undosys_ID_map_add(map, id);
+}
+
+ID *BKE_undosys_ID_map_lookup_with_prev(const UndoIDPtrMap *map, ID *id_src, ID *id_prev_match[2])
+{
+ if (id_src == id_prev_match[0]) {
+ return id_prev_match[1];
+ }
+ else {
+ ID *id_dst = BKE_undosys_ID_map_lookup(map, id_src);
+ id_prev_match[0] = id_src;
+ id_prev_match[1] = id_dst;
+ return id_dst;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 10fcfaa444f..5736c9331bf 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -43,7 +43,6 @@
#include "BLI_listbase.h"
#include "BKE_animsys.h"
-#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 5415fbb8ae1..d7fcd896e11 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_sound.h"
@@ -62,6 +63,8 @@
#include "ffmpeg_compat.h"
+struct StampData;
+
typedef struct FFMpegContext {
int ffmpeg_type;
int ffmpeg_codec;
@@ -94,6 +97,8 @@ typedef struct FFMpegContext {
bool audio_deinterleave;
int audio_sample_size;
+ struct StampData *stamp_data;
+
#ifdef WITH_AUDASPACE
AUD_Device *audio_mixdown_device;
#endif
@@ -577,24 +582,33 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
if (context->ffmpeg_preset) {
- char const *preset_name;
+ /* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not
+ * setting those properties conditionally based on the video codec,
+ * as the FFmpeg encoder simply ignores unknown settings anyway. */
+ char const *preset_name = NULL; /* used by h.264 */
+ char const *deadline_name = NULL; /* used by webm/vp9 */
switch (context->ffmpeg_preset) {
- case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break;
- case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break;
- case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break;
- case FFM_PRESET_FASTER: preset_name = "faster"; break;
- case FFM_PRESET_FAST: preset_name = "fast"; break;
- case FFM_PRESET_MEDIUM: preset_name = "medium"; break;
- case FFM_PRESET_SLOW: preset_name = "slow"; break;
- case FFM_PRESET_SLOWER: preset_name = "slower"; break;
- case FFM_PRESET_VERYSLOW: preset_name = "veryslow"; break;
+ case FFM_PRESET_GOOD:
+ preset_name = "medium";
+ deadline_name = "good";
+ break;
+ case FFM_PRESET_BEST:
+ preset_name = "slower";
+ deadline_name = "best";
+ break;
+ case FFM_PRESET_REALTIME:
+ preset_name = "superfast";
+ deadline_name = "realtime";
+ break;
default:
printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
- preset_name = NULL;
}
if (preset_name != NULL) {
av_dict_set(&opts, "preset", preset_name, 0);
}
+ if (deadline_name != NULL) {
+ av_dict_set(&opts, "deadline", deadline_name, 0);
+ }
}
#if 0
@@ -836,6 +850,12 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
av_dict_set(dict, key, buffer, 0);
}
+static void ffmpeg_add_metadata_callback(void *data, const char *propname, char *propvalue, int len)
+{
+ AVDictionary **metadata = (AVDictionary **)data;
+ av_dict_set(metadata, propname, propvalue, 0);
+}
+
static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
{
/* Handle to the output file */
@@ -994,6 +1014,11 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
goto fail;
}
}
+
+ if (context->stamp_data != NULL) {
+ BKE_stamp_info_callback(&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false);
+ }
+
if (avformat_write_header(of, NULL) < 0) {
BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination");
goto fail;
@@ -1168,6 +1193,7 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = preview;
+ context->stamp_data = BKE_stamp_info_from_scene_static(scene);
success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
#ifdef WITH_AUDASPACE
@@ -1659,7 +1685,7 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
{
BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM;
- rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
+ rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD;
rd->ffcodecdata.type = FFMPEG_MKV;
}
if (rd->ffcodecdata.type == FFMPEG_OGG) {
@@ -1734,6 +1760,7 @@ void *BKE_ffmpeg_context_create(void)
context->ffmpeg_autosplit = 0;
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = false;
+ context->stamp_data = NULL;
return context;
}
@@ -1741,9 +1768,13 @@ void *BKE_ffmpeg_context_create(void)
void BKE_ffmpeg_context_free(void *context_v)
{
FFMpegContext *context = context_v;
- if (context) {
- MEM_freeN(context);
+ if (context == NULL) {
+ return;
+ }
+ if (context->stamp_data) {
+ MEM_freeN(context->stamp_data);
}
+ MEM_freeN(context);
}
#endif /* WITH_FFMPEG */
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 6be9408ac1e..c4ad5acfe4b 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -74,7 +74,7 @@ void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const
void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
-int BLI_listbase_count_ex(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_sort_utils.h b/source/blender/blenlib/BLI_sort_utils.h
index e08f4e5ac83..f6bd80b30d3 100644
--- a/source/blender/blenlib/BLI_sort_utils.h
+++ b/source/blender/blenlib/BLI_sort_utils.h
@@ -32,7 +32,7 @@
* \note keep \a sort_value first,
* so cmp functions can be reused.
*/
-struct SortPointerByFloat {
+struct SortPtrByFloat {
float sort_value;
void *data;
};
@@ -42,7 +42,7 @@ struct SortIntByFloat {
int data;
};
-struct SortPointerByInt {
+struct SortPtrByInt {
int sort_value;
void *data;
};
@@ -58,4 +58,7 @@ int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_);
int BLI_sortutil_cmp_int(const void *a_, const void *b_);
int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_);
+int BLI_sortutil_cmp_ptr(const void *a_, const void *b_);
+int BLI_sortutil_cmp_ptr_reverse(const void *a_, const void *b_);
+
#endif /* __BLI_SORT_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index d137806c575..48be9d1842f 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -103,6 +103,20 @@ int BLI_string_find_split_words(
const char delim, int r_words[][2], int words_max)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/** \name String Copy/Format Macros
+ * Avoid repeating destination with `sizeof(..)`.
+ * \note `ARRAY_SIZE` allows pointers on some platforms.
+ * \{ */
+#define STRNCPY(dst, src) \
+ BLI_strncpy(dst, src, ARRAY_SIZE(dst))
+#define STRNCPY_RLEN(dst, src) \
+ BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
+#define SNPRINTF(dst, format, ...) \
+ BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
+#define SNPRINTF_RLEN(dst, format, ...) \
+ BLI_snprintf_rlen(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 32504a88b48..21542d0d6e1 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -77,6 +77,16 @@ size_t BLI_str_partition_ex_utf8(
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
+/** \name String Copy/Format Macros
+ * Avoid repeating destination with `sizeof(..)`.
+ * \note `ARRAY_SIZE` allows pointers on some platforms.
+ * \{ */
+#define STRNCPY_UTF8(dst, src) \
+ BLI_strncpy_utf8(dst, src, ARRAY_SIZE(dst))
+#define STRNCPY_UTF8_RLEN(dst, src) \
+ BLI_strncpy_utf8_rlen(dst, src, ARRAY_SIZE(dst))
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 11c8a586784..46b3748c7ce 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -411,7 +411,7 @@ extern "C" {
} (void)0
/* assuming a static array */
-#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__)
+#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) && !defined(__INTEL_COMPILER)
# define ARRAY_SIZE(arr) \
((sizeof(struct {int isnt_array : ((const void *)&(arr) == &(arr)[0]);}) * 0) + \
(sizeof(arr) / sizeof(*(arr))))
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 96c3972d802..b87fed571b7 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -484,7 +484,7 @@ void BLI_freelistN(ListBase *listbase)
*
* \note Use to avoid redundant looping.
*/
-int BLI_listbase_count_ex(const ListBase *listbase, const int count_max)
+int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
{
Link *link;
int count = 0;
diff --git a/source/blender/blenlib/intern/sort_utils.c b/source/blender/blenlib/intern/sort_utils.c
index c75e8e7455f..2d55e77b98b 100644
--- a/source/blender/blenlib/intern/sort_utils.c
+++ b/source/blender/blenlib/intern/sort_utils.c
@@ -37,6 +37,10 @@ struct SortAnyByInt {
int sort_value;
};
+struct SortAnyByPtr {
+ const void *sort_value;
+};
+
int BLI_sortutil_cmp_float(const void *a_, const void *b_)
{
const struct SortAnyByFloat *a = a_;
@@ -72,3 +76,21 @@ int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_)
else if (a->sort_value > b->sort_value) return -1;
else return 0;
}
+
+int BLI_sortutil_cmp_ptr(const void *a_, const void *b_)
+{
+ const struct SortAnyByPtr *a = a_;
+ const struct SortAnyByPtr *b = b_;
+ if (a->sort_value > b->sort_value) return 1;
+ else if (a->sort_value < b->sort_value) return -1;
+ else return 0;
+}
+
+int BLI_sortutil_cmp_ptr_reverse(const void *a_, const void *b_)
+{
+ const struct SortAnyByPtr *a = a_;
+ const struct SortAnyByPtr *b = b_;
+ if (a->sort_value < b->sort_value) return 1;
+ else if (a->sort_value > b->sort_value) return -1;
+ else return 0;
+}
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 4fd2e227bc5..0b4ff13c7bd 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -147,6 +147,8 @@ void BLO_update_defaults_startup_blend(struct Main *mainvar);
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
+struct Main *BLO_main_from_memfile(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index d3c0130a63b..b713b963056 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -33,6 +33,8 @@
* \ingroup blenloader
*/
+struct Scene;
+
typedef struct {
void *next, *prev;
const char *buf;
@@ -47,6 +49,12 @@ typedef struct MemFile {
size_t size;
} MemFile;
+typedef struct MemFileUndoData {
+ char filename[1024]; /* FILE_MAX */
+ MemFile memfile;
+ size_t undo_size;
+} MemFileUndoData;
+
/* actually only used writefile.c */
extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size);
@@ -54,5 +62,9 @@ extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *bu
extern void BLO_memfile_free(MemFile *memfile);
extern void BLO_memfile_merge(MemFile *first, MemFile *second);
-#endif
+/* utilities */
+extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene);
+extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename);
+
+#endif /* __BLO_UNDOFILE_H__ */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e85af67b105..a4739240cb4 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2235,6 +2235,10 @@ static void direct_link_id(FileData *fd, ID *id)
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
id->py_instance = NULL;
+
+ /* That way datablock reading not going through main read_libblock() function are still in a clear tag state.
+ * (glowering at certain nodetree fake datablock here...). */
+ id->tag = 0;
}
/* ************ READ CurveMapping *************** */
@@ -3708,15 +3712,11 @@ static void lib_link_text(FileData *fd, Main *main)
static void direct_link_text(FileData *fd, Text *text)
{
TextLine *ln;
-
+
text->name = newdataadr(fd, text->name);
-
- text->undo_pos = -1;
- text->undo_len = TXT_INIT_UNDO;
- text->undo_buf = MEM_mallocN(text->undo_len, "undo buf");
-
+
text->compiled = NULL;
-
+
#if 0
if (text->flags & TXT_ISEXT) {
BKE_text_reload(text);
@@ -5076,6 +5076,7 @@ static void direct_link_pose(FileData *fd, bPose *pose)
link_list(fd, &pose->agroups);
pose->chanhash = NULL;
+ pose->chan_array = NULL;
for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
pchan->bone = NULL;
@@ -6300,7 +6301,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
wm->defaultconf = NULL;
wm->addonconf = NULL;
wm->userconf = NULL;
-
+ wm->undo_stack = NULL;
+
BLI_listbase_clear(&wm->jobs);
BLI_listbase_clear(&wm->drags);
@@ -8236,7 +8238,6 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
if (!id)
return blo_nextbhead(fd, bhead);
- id->tag = tag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
@@ -8245,12 +8246,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
+ /* That way, we know which datablock needs do_versions (required currently for linking). */
+ id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
return blo_nextbhead(fd, bhead);
}
- /* That way, we know which datablock needs do_versions (required currently for linking). */
- id->tag |= LIB_TAG_NEW;
-
/* need a name for the mallocN, just for debugging and sane prints on leaks */
allocname = dataname(GS(id->name));
@@ -8259,7 +8260,11 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
/* init pointers direct data */
direct_link_id(fd, id);
-
+
+ /* That way, we know which datablock needs do_versions (required currently for linking). */
+ /* Note: doing this after driect_link_id(), which resets that field. */
+ id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
switch (GS(id->name)) {
case ID_WM:
direct_link_windowmanager(fd, (wmWindowManager *)id);
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index ffc7d7c83f5..f6584ecf25f 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -34,6 +34,15 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* open/close */
+#ifndef _WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "MEM_guardedalloc.h"
@@ -42,6 +51,9 @@
#include "BLI_blenlib.h"
#include "BLO_undofile.h"
+#include "BLO_readfile.h"
+
+#include "BKE_main.h"
/* keep last */
#include "BLI_strict_flags.h"
@@ -124,3 +136,69 @@ void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsi
current->size += size;
}
}
+
+struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *oldmain, struct Scene **r_scene)
+{
+ struct Main *bmain_undo = NULL;
+ BlendFileData *bfd = BLO_read_from_memfile(oldmain, oldmain->name, memfile, NULL, BLO_READ_SKIP_NONE);
+
+ if (bfd) {
+ bmain_undo = bfd->main;
+ if (r_scene) {
+ *r_scene = bfd->curscene;
+ }
+
+ MEM_freeN(bfd);
+ }
+
+ return bmain_undo;
+}
+
+
+/**
+ * Saves .blend using undo buffer.
+ *
+ * \return success.
+ */
+bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
+{
+ MemFileChunk *chunk;
+ int file, oflags;
+
+ /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK,
+ * however if this is ever executed explicitly by the user, we may want to allow writing to symlinks.
+ */
+
+ oflags = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC;
+#ifdef O_NOFOLLOW
+ /* use O_NOFOLLOW to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */
+ oflags |= O_NOFOLLOW;
+#else
+ /* TODO(sergey): How to deal with symlinks on windows? */
+# ifndef _MSC_VER
+# warning "Symbolic links will be followed on undo save, possibly causing CVE-2008-1103"
+# endif
+#endif
+ file = BLI_open(filename, oflags, 0666);
+
+ if (file == -1) {
+ fprintf(stderr, "Unable to save '%s': %s\n",
+ filename, errno ? strerror(errno) : "Unknown error opening file");
+ return false;
+ }
+
+ for (chunk = memfile->chunks.first; chunk; chunk = chunk->next) {
+ if ((size_t)write(file, chunk->buf, chunk->size) != chunk->size) {
+ break;
+ }
+ }
+
+ close(file);
+
+ if (chunk) {
+ fprintf(stderr, "Unable to save '%s': %s\n",
+ filename, errno ? strerror(errno) : "Unknown error writing file");
+ return false;
+ }
+ return true;
+}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index f1c40aae399..e9de7919d25 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1796,6 +1796,23 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ int preset = scene->r.ffcodecdata.ffmpeg_preset;
+ if (preset == FFM_PRESET_NONE || preset >= FFM_PRESET_GOOD) {
+ continue;
+ }
+ if (preset <= FFM_PRESET_FAST) {
+ preset = FFM_PRESET_REALTIME;
+ }
+ else if (preset >= FFM_PRESET_SLOW) {
+ preset = FFM_PRESET_BEST;
+ }
+ else {
+ preset = FFM_PRESET_GOOD;
+ }
+ scene->r.ffcodecdata.ffmpeg_preset = preset;
+ }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index c4b29e91fb4..7e35866887d 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -685,7 +685,7 @@ int bmesh_elem_check(void *element, const char htype)
err |= IS_FACE_LOOP_WRONG_RADIAL_LENGTH;
}
- if (bmesh_disk_count_ex(l_iter->v, 2) < 2) {
+ if (bmesh_disk_count_at_most(l_iter->v, 2) < 2) {
err |= IS_FACE_LOOP_WRONG_DISK_LENGTH;
}
}
@@ -1785,7 +1785,7 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(
return NULL;
}
- if (bmesh_disk_count_ex(v_kill, 3) == 2) {
+ if (bmesh_disk_count_at_most(v_kill, 3) == 2) {
#ifndef NDEBUG
int valence1, valence2;
BMLoop *l;
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 961cc458784..4290f94bba1 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -65,7 +65,7 @@
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
/* logic for 3 or more is identical */
- const int len = BM_vert_edge_count_ex(v, 3);
+ const int len = BM_vert_edge_count_at_most(v, 3);
if (len == 1) {
BM_vert_kill(bm, v); /* will kill edges too */
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 4dcf97e3f35..daee22ffe76 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -55,7 +55,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
-int bmesh_disk_count_ex(const BMVert *v, const int count_max);
+int bmesh_disk_count_at_most(const BMVert *v, const int count_max);
int bmesh_disk_count(const BMVert *v);
/**
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 3a76f4ca271..ab2f017d103 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -799,9 +799,9 @@ int BM_vert_edge_count(const BMVert *v)
return bmesh_disk_count(v);
}
-int BM_vert_edge_count_ex(const BMVert *v, const int count_max)
+int BM_vert_edge_count_at_most(const BMVert *v, const int count_max)
{
- return bmesh_disk_count_ex(v, count_max);
+ return bmesh_disk_count_at_most(v, count_max);
}
int BM_vert_edge_count_nonwire(const BMVert *v)
@@ -835,7 +835,7 @@ int BM_edge_face_count(const BMEdge *e)
return count;
}
-int BM_edge_face_count_ex(const BMEdge *e, const int count_max)
+int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
{
int count = 0;
@@ -863,9 +863,9 @@ int BM_vert_face_count(const BMVert *v)
return bmesh_disk_facevert_count(v);
}
-int BM_vert_face_count_ex(const BMVert *v, int count_max)
+int BM_vert_face_count_at_most(const BMVert *v, int count_max)
{
- return bmesh_disk_facevert_count_ex(v, count_max);
+ return bmesh_disk_facevert_count_at_most(v, count_max);
}
/**
@@ -1044,7 +1044,7 @@ static int bm_loop_region_count__clear(BMLoop *l)
/**
* The number of loops connected to this loop (not including disconnected regions).
*/
-int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total)
+int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
{
const int count = bm_loop_region_count__recursive(l->e, l->v);
const int count_total = bm_loop_region_count__clear(l);
@@ -1059,7 +1059,7 @@ int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total)
int BM_loop_region_loops_count(BMLoop *l)
{
- return BM_loop_region_loops_count_ex(l, NULL);
+ return BM_loop_region_loops_count_at_most(l, NULL);
}
/**
@@ -1071,7 +1071,7 @@ bool BM_vert_is_manifold_region(const BMVert *v)
BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
if (l_first) {
int count, count_total;
- count = BM_loop_region_loops_count_ex(l_first, &count_total);
+ count = BM_loop_region_loops_count_at_most(l_first, &count_total);
return (count == count_total);
}
return true;
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index c9fce96c798..e602c63da94 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -70,17 +70,17 @@ BMFace *BM_edge_pair_share_face_by_len(
const bool allow_adjacent) ATTR_NONNULL();
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == n)
-#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == (n) + 1)
-int BM_vert_edge_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == n)
+#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1)
+int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_ex(e, (n) + 1) == n)
-#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_ex(e, (n) + 1) == (n) + 1)
-int BM_edge_face_count_ex(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n)
+#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1)
+int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_ex(v, (n) + 1) == n)
-#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_ex(v, (n) + 1) == (n) + 1)
-int BM_vert_face_count_ex(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n)
+#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1)
+int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -103,7 +103,7 @@ bool BM_edge_is_contiguous_loop_cd(
const int cd_loop_type, const int cd_loop_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_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 8e484841568..8aa9502c0f7 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -244,7 +244,7 @@ int bmesh_disk_count(const BMVert *v)
return count;
}
-int bmesh_disk_count_ex(const BMVert *v, const int count_max)
+int bmesh_disk_count_at_most(const BMVert *v, const int count_max)
{
int count = 0;
if (v->e) {
@@ -267,7 +267,7 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
if (!BM_vert_in_edge(e, v)) {
return false;
}
- if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) {
+ if (len == 0 || bmesh_disk_count_at_most(v, len + 1) != len) {
return false;
}
@@ -307,7 +307,7 @@ int bmesh_disk_facevert_count(const BMVert *v)
return count;
}
-int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
+int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
{
/* is there an edge on this vert at all */
int count = 0;
@@ -318,7 +318,7 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
e_first = e_iter = v->e;
do {
if (e_iter->l) {
- count += bmesh_radial_facevert_count_ex(e_iter->l, v, count_max - count);
+ count += bmesh_radial_facevert_count_at_most(e_iter->l, v, count_max - count);
if (count == count_max) {
break;
}
@@ -560,7 +560,7 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
return count;
}
-int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max)
+int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max)
{
const BMLoop *l_iter;
int count = 0;
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 0efb25da37c..974b276f8b3 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -49,7 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) A
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int bmesh_disk_facevert_count_at_most(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();
@@ -63,7 +63,7 @@ void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
-int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 69198ff35ab..b1053e6d8c2 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -270,7 +270,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BMFace *f;
BMEdge *e;
/* data: edge-to-join, sort_value: error weight */
- struct SortPointerByFloat *jedges;
+ struct SortPtrByFloat *jedges;
unsigned i, totedge;
uint totedge_tag = 0;
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 6ae82ddd836..334dff20d52 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -592,6 +592,12 @@ void AnimationImporter:: Assign_color_animations(const COLLADAFW::UniqueId& list
BLI_strncpy(rna_path, anim_type, sizeof(rna_path));
const COLLADAFW::AnimationList *animlist = animlist_map[listid];
+ if (animlist == NULL)
+ {
+ fprintf(stderr, "Collada: No animlist found for ID: %s of type %s\n", listid.toAscii().c_str(), anim_type);
+ return;
+ }
+
const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
//all the curves belonging to the current binding
std::vector<FCurve *> animcurves;
@@ -889,11 +895,22 @@ static const double get_aspect_ratio(const COLLADAFW::Camera *camera)
return aspect;
}
+static ListBase &get_animation_curves(Material *ma)
+{
+ bAction *act;
+ if (!ma->adt || !ma->adt->action)
+ act = verify_adt_action((ID *)&ma->id, 1);
+ else
+ act = ma->adt->action;
+
+ return act->curves;
+}
void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
std::multimap<COLLADAFW::UniqueId, Object *>& object_map,
- std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map)
+ std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
+ std::map<COLLADAFW::UniqueId, Material*> uid_material_map)
{
bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
COLLADAFW::UniqueId uid = node->getUniqueId();
@@ -1071,11 +1088,6 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
}
}
if (animType->material != 0) {
- Material *ma = give_current_material(ob, 1);
- if (!ma->adt || !ma->adt->action) act = verify_adt_action((ID *)&ma->id, 1);
- else act = ma->adt->action;
-
- ListBase *AnimCurves = &(act->curves);
const COLLADAFW::InstanceGeometryPointerArray& nodeGeoms = node->getInstanceGeometries();
for (unsigned int i = 0; i < nodeGeoms.getCount(); i++) {
@@ -1084,30 +1096,36 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
const COLLADAFW::UniqueId & matuid = matBinds[j].getReferencedMaterial();
const COLLADAFW::Effect *ef = (COLLADAFW::Effect *) (FW_object_map[matuid]);
if (ef != NULL) { /* can be NULL [#28909] */
- const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects();
+ Material *ma = uid_material_map[matuid];
+ if (!ma) {
+ fprintf(stderr, "Collada: Node %s refers to undefined material\n", node->getName().c_str());
+ continue;
+ }
+ ListBase &AnimCurves = get_animation_curves(ma);
+ const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects();
COLLADAFW::EffectCommon *efc = commonEffects[0];
if ((animType->material & MATERIAL_SHININESS) != 0) {
const COLLADAFW::FloatOrParam *shin = &(efc->getShininess());
- const COLLADAFW::UniqueId& listid = shin->getAnimationList();
- Assign_float_animations(listid, AnimCurves, "specular_hardness");
+ const COLLADAFW::UniqueId& listid = shin->getAnimationList();
+ Assign_float_animations(listid, &AnimCurves, "specular_hardness");
}
if ((animType->material & MATERIAL_IOR) != 0) {
const COLLADAFW::FloatOrParam *ior = &(efc->getIndexOfRefraction());
- const COLLADAFW::UniqueId& listid = ior->getAnimationList();
- Assign_float_animations(listid, AnimCurves, "raytrace_transparency.ior");
+ const COLLADAFW::UniqueId& listid = ior->getAnimationList();
+ Assign_float_animations(listid, &AnimCurves, "raytrace_transparency.ior");
}
if ((animType->material & MATERIAL_SPEC_COLOR) != 0) {
const COLLADAFW::ColorOrTexture *cot = &(efc->getSpecular());
- const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList();
- Assign_color_animations(listid, AnimCurves, "specular_color");
+ const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList();
+ Assign_color_animations(listid, &AnimCurves, "specular_color");
}
if ((animType->material & MATERIAL_DIFF_COLOR) != 0) {
const COLLADAFW::ColorOrTexture *cot = &(efc->getDiffuse());
- const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList();
- Assign_color_animations(listid, AnimCurves, "diffuse_color");
+ const COLLADAFW::UniqueId& listid = cot->getColor().getAnimationList();
+ Assign_color_animations(listid, &AnimCurves, "diffuse_color");
}
}
}
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
index 1f2de2f3162..e25116cac9f 100644
--- a/source/blender/collada/AnimationImporter.h
+++ b/source/blender/collada/AnimationImporter.h
@@ -156,7 +156,8 @@ public:
void translate_Animations(COLLADAFW::Node * Node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
std::multimap<COLLADAFW::UniqueId, Object*>& object_map,
- std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map);
+ std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map,
+ std::map<COLLADAFW::UniqueId, Material*> uid_material_map);
AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map );
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 08ac6e65c11..ce0d296843b 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -320,7 +320,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW
translate_anim_recursive(node, node, parob);
}
else {
- anim_importer.translate_Animations(node, root_map, object_map, FW_object_map);
+ anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map);
COLLADAFW::NodePointerArray &children = node->getChildNodes();
for (i = 0; i < children.getCount(); i++) {
translate_anim_recursive(children[i], node, NULL);
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index 81891d853d2..1399749fc8d 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -105,7 +105,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
}
/* returns the image view to use for the current active view */
- if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
+ if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
const int view_image = imageuser->view;
const bool is_allview = (view_image == 0); /* if view selected == All (0) */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 15e3ea3e10f..7b2914303ce 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -114,39 +114,6 @@ extern "C" {
namespace DEG {
-namespace {
-
-struct BuilderWalkUserData {
- DepsgraphNodeBuilder *builder;
-};
-
-static void modifier_walk(void *user_data,
- struct Object * /*object*/,
- struct Object **obpoin,
- int /*cb_flag*/)
-{
- BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
- if (*obpoin) {
- data->builder->build_object(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(NULL, (Object *)id);
- }
- }
-}
-
-} /* namespace */
-
/* ************ */
/* Node Builder */
@@ -342,7 +309,7 @@ void DepsgraphNodeBuilder::build_object(Base *base, Object *object)
if (object->modifiers.first != NULL) {
BuilderWalkUserData data;
data.builder = this;
- modifiers_foreachObjectLink(object, modifier_walk, &data);
+ modifiers_foreachIDLink(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != NULL) {
@@ -1053,6 +1020,11 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture)
build_image(texture->ima);
}
}
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(&texture->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER);
}
void DepsgraphNodeBuilder::build_image(Image *image) {
@@ -1131,4 +1103,50 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
DEG_OPCODE_MOVIECLIP_EVAL);
}
+/* **** ID traversal callbacks functions **** */
+
+void DepsgraphNodeBuilder::modifier_walk(void *user_data,
+ struct Object * /*object*/,
+ struct ID **idpoin,
+ int /*cb_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ ID *id = *idpoin;
+ if (id == NULL) {
+ return;
+ }
+ switch (GS(id->name)) {
+ case ID_OB:
+ data->builder->build_object(NULL, (Object *)id);
+ break;
+ case ID_TE:
+ data->builder->build_texture((Tex *)id);
+ break;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ ID *id = *idpoin;
+ if (id == NULL) {
+ return;
+ }
+ switch (GS(id->name)) {
+ case ID_OB:
+ data->builder->build_object(NULL, (Object *)id);
+ break;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 9d47dc6bced..d64aee11536 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -132,7 +132,7 @@ struct DepsgraphNodeBuilder {
void build_object_data(Object *object);
void build_object_transform(Object *object);
void build_object_constraints(Object *object);
- void build_pose_constraints(Object *object, bPoseChannel *pchan);
+ void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
void build_rigidbody(Scene *scene);
void build_particles(Object *object);
void build_cloth(Object *object);
@@ -165,6 +165,20 @@ struct DepsgraphNodeBuilder {
void build_movieclip(MovieClip *clip);
protected:
+ struct BuilderWalkUserData {
+ DepsgraphNodeBuilder *builder;
+ };
+
+ static void modifier_walk(void *user_data,
+ struct Object *object,
+ struct ID **idpoin,
+ int cb_flag);
+
+ static void constraint_walk(bConstraint *constraint,
+ ID **idpoin,
+ bool is_reference,
+ void *user_data);
+
/* State which never changes, same for the whole builder time. */
Main *bmain_;
Depsgraph *graph_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 73bbbcfa0b3..9cfe83e0087 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -49,6 +49,7 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_constraint.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -64,16 +65,28 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_pose_constraints(Object *object, bPoseChannel *pchan)
+void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
+ bPoseChannel *pchan,
+ int pchan_index)
{
- /* create node for constraint stack */
+ /* Pull indirect dependencies via constraints. */
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
+ /* Create node for constraint stack. */
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- function_bind(BKE_pose_constraints_evaluate, _1, scene_, object, pchan),
+ function_bind(BKE_pose_constraints_evaluate,
+ _1,
+ scene_,
+ object,
+ pchan_index),
DEG_OPCODE_BONE_CONSTRAINTS);
}
/* IK Solver Eval Steps */
-void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_ik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con)
{
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
@@ -89,14 +102,22 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bC
return;
}
+ int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
+ BLI_assert(rootchan_index != -1);
/* Operation node for evaluating/running IK Solver. */
add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
- function_bind(BKE_pose_iktree_evaluate, _1, scene_, object, rootchan),
+ function_bind(BKE_pose_iktree_evaluate,
+ _1,
+ scene_,
+ object,
+ rootchan_index),
DEG_OPCODE_POSE_IK_SOLVER);
}
/* Spline IK Eval Steps */
-void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con)
{
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
@@ -106,8 +127,14 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pch
/* Operation node for evaluating/running Spline IK Solver.
* Store the "root bone" of this chain in the solver, so it knows where to start.
*/
+ int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
+ BLI_assert(rootchan_index != -1);
add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
- function_bind(BKE_pose_splineik_evaluate, _1, scene_, object, rootchan),
+ function_bind(BKE_pose_splineik_evaluate,
+ _1,
+ scene_,
+ object,
+ rootchan_index),
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
}
@@ -178,22 +205,32 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
/* pose eval context */
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
- function_bind(BKE_pose_eval_init, _1, scene_, object, object->pose),
+ function_bind(BKE_pose_eval_init,
+ _1,
+ scene_,
+ object),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
- function_bind(BKE_pose_eval_init_ik, _1, scene_, object, object->pose),
+ function_bind(BKE_pose_eval_init_ik,
+ _1,
+ scene_,
+ object),
DEG_OPCODE_POSE_INIT_IK);
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
- function_bind(BKE_pose_eval_flush, _1, scene_, object, object->pose),
+ function_bind(BKE_pose_eval_flush,
+ _1,
+ scene_,
+ object),
DEG_OPCODE_POSE_DONE);
op_node->set_as_exit();
/* bones */
+ int pchan_index = 0;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
/* Node for bone evaluation. */
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
@@ -201,7 +238,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
op_node->set_as_entry();
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan),
+ function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan_index),
DEG_OPCODE_BONE_POSE_PARENT);
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
@@ -209,7 +246,10 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
DEG_OPCODE_BONE_READY);
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- function_bind(BKE_pose_bone_done, _1, pchan),
+ function_bind(BKE_pose_bone_done,
+ _1,
+ object,
+ pchan_index),
DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
/* Custom properties. */
@@ -222,7 +262,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
}
/* Constraints. */
if (pchan->constraints.first != NULL) {
- build_pose_constraints(object, pchan);
+ build_pose_constraints(object, pchan, pchan_index);
}
/**
* IK Solvers.
@@ -232,7 +272,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* base transforms of a bunch of bones is done)
*
* Unsolved Issues:
- * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Care is needed to ensure that multi-headed trees work out the same
+ * as in ik-tree building.
* - Animated chain-lengths are a problem...
*/
LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
@@ -249,6 +290,13 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
break;
}
}
+
+ /* Custom shape. */
+ if (pchan->custom != NULL) {
+ build_object(NULL, pchan->custom);
+ }
+
+ pchan_index++;
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 40db9d1b5f1..4ebc0804479 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -114,39 +114,6 @@ extern "C" {
namespace DEG {
-namespace {
-
-struct BuilderWalkUserData {
- DepsgraphRelationBuilder *builder;
-};
-
-void modifier_walk(void *user_data,
- struct Object * /*object*/,
- struct Object **obpoin,
- int /*cb_flag*/)
-{
- BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
- if (*obpoin) {
- data->builder->build_object(*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((Object *)id);
- }
- }
-}
-
-} /* namespace */
-
/* ***************** */
/* Relations Builder */
@@ -459,7 +426,7 @@ void DepsgraphRelationBuilder::build_object(Object *object)
if (object->modifiers.first != NULL) {
BuilderWalkUserData data;
data.builder = this;
- modifiers_foreachObjectLink(object, modifier_walk, &data);
+ modifiers_foreachIDLink(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != NULL) {
@@ -1874,4 +1841,43 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
build_animdata(&clip->id);
}
+/* **** ID traversal callbacks functions **** */
+
+void DepsgraphRelationBuilder::modifier_walk(void *user_data,
+ struct Object * /*object*/,
+ struct ID **idpoin,
+ int /*cb_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ ID *id = *idpoin;
+ if (id == NULL) {
+ return;
+ }
+ switch (GS(id->name)) {
+ case ID_OB:
+ data->builder->build_object((Object *)id);
+ break;
+ case ID_TE:
+ data->builder->build_texture((Tex *)id);
+ break;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+void DepsgraphRelationBuilder::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((Object *)id);
+ }
+ }
+}
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index c4d77d97232..d1ca0b6c7dd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -313,6 +313,20 @@ protected:
const KeyTo& key_to);
private:
+ struct BuilderWalkUserData {
+ DepsgraphRelationBuilder *builder;
+ };
+
+ static void modifier_walk(void *user_data,
+ struct Object *object,
+ struct ID **idpoin,
+ int cb_flag);
+
+ static void constraint_walk(bConstraint *con,
+ ID **idpoin,
+ bool is_reference,
+ void *user_data);
+
/* State which never changes, same for the whole builder time. */
Main *bmain_;
Depsgraph *graph_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index b9850209d7d..2eee1671795 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -51,6 +51,7 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_constraint.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -411,6 +412,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* constraints */
if (pchan->constraints.first != NULL) {
+ /* Build relations for indirectly linked objects. */
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
+
/* constraints stack and constraint dependencies */
build_constraints(&object->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
@@ -436,6 +442,11 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* assume that all bones must be done for the pose to be ready (for deformers) */
add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link");
+
+ /* Custom shape. */
+ if (pchan->custom != NULL) {
+ build_object(pchan->custom);
+ }
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 66ddaa6b0d5..da7ac03146e 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -531,12 +531,14 @@ void DEG_debug_print_eval(const char *function_name,
if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
- printf("%s on %s %s(%p)%s\n",
- function_name,
- object_name,
- DEG::deg_color_for_pointer(object_address).c_str(),
- object_address,
- DEG::deg_color_end().c_str());
+ fprintf(stdout,
+ "%s on %s %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str());
+ fflush(stdout);
}
void DEG_debug_print_eval_subdata(const char *function_name,
@@ -549,17 +551,19 @@ void DEG_debug_print_eval_subdata(const char *function_name,
if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
- printf("%s on %s %s(%p)%s %s %s %s(%p)%s\n",
- function_name,
- object_name,
- DEG::deg_color_for_pointer(object_address).c_str(),
- object_address,
- DEG::deg_color_end().c_str(),
- subdata_comment,
- subdata_name,
- DEG::deg_color_for_pointer(subdata_address).c_str(),
- subdata_address,
- DEG::deg_color_end().c_str());
+ fprintf(stdout,
+ "%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ subdata_comment,
+ subdata_name,
+ DEG::deg_color_for_pointer(subdata_address).c_str(),
+ subdata_address,
+ DEG::deg_color_end().c_str());
+ fflush(stdout);
}
void DEG_debug_print_eval_subdata_index(const char *function_name,
@@ -573,18 +577,20 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
- printf("%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
- function_name,
- object_name,
- DEG::deg_color_for_pointer(object_address).c_str(),
- object_address,
- DEG::deg_color_end().c_str(),
- subdata_comment,
- subdata_name,
- subdata_index,
- DEG::deg_color_for_pointer(subdata_address).c_str(),
- subdata_address,
- DEG::deg_color_end().c_str());
+ fprintf(stdout,
+ "%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ subdata_comment,
+ subdata_name,
+ subdata_index,
+ DEG::deg_color_for_pointer(subdata_address).c_str(),
+ subdata_address,
+ DEG::deg_color_end().c_str());
+ fflush(stdout);
}
void DEG_debug_print_eval_time(const char *function_name,
@@ -595,11 +601,13 @@ void DEG_debug_print_eval_time(const char *function_name,
if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
- printf("%s on %s %s(%p)%s at time %f\n",
- function_name,
- object_name,
- DEG::deg_color_for_pointer(object_address).c_str(),
- object_address,
- DEG::deg_color_end().c_str(),
- time);
+ fprintf(stdout,
+ "%s on %s %s(%p)%s at time %f\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ time);
+ fflush(stdout);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 92518ba73e4..fc71b5ccb7b 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -252,6 +252,9 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
const unsigned int layers)
{
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
/* Nothing to update, early out. */
if (BLI_gset_len(graph->entry_tags) == 0) {
return;
@@ -262,9 +265,6 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
graph->layers);
const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
- /* Set time for the current graph evaluation context. */
- TimeSourceDepsNode *time_src = graph->find_time_source();
- eval_ctx->ctime = time_src->cfra;
/* Set up evaluation context for depsgraph itself. */
DepsgraphEvalState state;
state.eval_ctx = eval_ctx;
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index be8829b0418..17a8eef1bdb 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -59,6 +59,7 @@ if(WITH_BLENDER)
add_subdirectory(space_userpref)
add_subdirectory(space_view3d)
add_subdirectory(transform)
+ add_subdirectory(undo)
add_subdirectory(util)
add_subdirectory(uvedit)
endif()
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index e9ab949dc95..8b922082fe8 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2721,7 +2721,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
if (ob != sce->obedit)
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 8d77460e197..8106be79521 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -62,7 +62,7 @@
#include "UI_resources.h"
#include "ED_anim_api.h"
-#include "ED_util.h"
+#include "ED_undo.h"
/* ********************************************** */
/* UI STUFF */
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 2fb216c2ef8..3dd41f25e09 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -42,7 +42,7 @@
#include "BKE_context.h"
#include "ED_armature.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "BIF_retarget.h"
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 36e6ec4ba7f..f27d68d0634 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -33,21 +33,31 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
#include "ED_armature.h"
+#include "ED_object.h"
#include "ED_util.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoArmature {
EditBone *act_edbone;
ListBase lb;
+ size_t undo_size;
} UndoArmature;
-static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
+static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
{
- UndoArmature *uarm = uarmv;
- bArmature *arm = armv;
EditBone *ebone;
ED_armature_ebone_listbase_free(arm->edbo);
@@ -65,48 +75,117 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
ED_armature_ebone_listbase_temp_clear(arm->edbo);
}
-static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
+static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
{
- bArmature *arm = armv;
- UndoArmature *uarm;
- EditBone *ebone;
+ BLI_assert(BLI_array_is_zeroed(uarm, 1));
- uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
+ /* TODO: include size of ID-properties. */
+ uarm->undo_size = 0;
ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo);
/* active bone */
if (arm->act_edbone) {
- ebone = arm->act_edbone;
+ EditBone *ebone = arm->act_edbone;
uarm->act_edbone = ebone->temp.ebone;
}
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
+ for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
+ uarm->undo_size += sizeof(EditBone);
+ }
+
return uarm;
}
-static void free_undoBones(void *uarmv)
+static void undoarm_free_data(UndoArmature *uarm)
{
- UndoArmature *uarm = uarmv;
-
ED_armature_ebone_listbase_free(&uarm->lb);
-
- MEM_freeN(uarm);
}
-static void *get_armature_edit(bContext *C)
+static Object *editarm_object_from_context(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (obedit && obedit->type == OB_ARMATURE) {
- return obedit->data;
+ bArmature *arm = obedit->data;
+ if (arm->edbo != NULL) {
+ return obedit;
+ }
}
return NULL;
}
-/* and this is all the undo system needs to know */
-void undo_push_armature(bContext *C, const char *name)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ArmatureUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoArmature data;
+} ArmatureUndoStep;
+
+static bool armature_undosys_poll(bContext *C)
{
- // XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+ return editarm_object_from_context(C) != NULL;
}
+
+static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ us->obedit_ref.ptr = editarm_object_from_context(C);
+ bArmature *arm = us->obedit_ref.ptr->data;
+ undoarm_from_editarm(&us->data, arm);
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(armature_undosys_poll(C));
+
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ bArmature *arm = obedit->data;
+ undoarm_to_editarm(&us->data, arm);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void armature_undosys_step_free(UndoStep *us_p)
+{
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ undoarm_free_data(&us->data);
+}
+
+static void armature_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+}
+
+/* Export for ED_undo_sys. */
+void ED_armature_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit Armature";
+ ut->poll = armature_undosys_poll;
+ ut->step_encode = armature_undosys_step_encode;
+ ut->step_decode = armature_undosys_step_decode;
+ ut->step_free = armature_undosys_step_free;
+
+ ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ArmatureUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 2f536ebff6e..d0c467b2d2c 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -81,42 +81,55 @@ Object *ED_pose_object_from_context(bContext *C)
}
/* This function is used to process the necessary updates for */
-void ED_armature_enter_posemode(bContext *C, Base *base)
+bool ED_object_posemode_enter_ex(Object *ob)
{
- ReportList *reports = CTX_wm_reports(C);
- Object *ob = base->object;
-
- if (ID_IS_LINKED(ob)) {
- BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
- return;
- }
+ BLI_assert(!ID_IS_LINKED(ob));
+ bool ok = false;
switch (ob->type) {
case OB_ARMATURE:
ob->restore_mode = ob->mode;
ob->mode |= OB_MODE_POSE;
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
-
+ ok = true;
+
break;
default:
- return;
+ break;
}
-
- /* XXX: disabled as this would otherwise cause a nasty loop... */
- //ED_object_mode_toggle(C, ob->mode);
+
+ return ok;
+}
+bool ED_object_posemode_enter(bContext *C, Object *ob)
+{
+ ReportList *reports = CTX_wm_reports(C);
+ if (ID_IS_LINKED(ob)) {
+ BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
+ return false;
+ }
+ bool ok = ED_object_posemode_enter_ex(ob);
+ if (ok) {
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+ }
+ return ok;
}
-void ED_armature_exit_posemode(bContext *C, Base *base)
+bool ED_object_posemode_exit_ex(Object *ob)
{
- if (base) {
- Object *ob = base->object;
-
+ bool ok = false;
+ if (ob) {
ob->restore_mode = ob->mode;
ob->mode &= ~OB_MODE_POSE;
-
+ ok = true;
+ }
+ return ok;
+}
+bool ED_object_posemode_exit(bContext *C, Object *ob)
+{
+ bool ok = ED_object_posemode_exit_ex(ob);
+ if (ok) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
}
+ return ok;
}
/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 4feb1681349..a44accd1cea 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -525,7 +525,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* Make sure data from this file is usable for pose paste. */
- if (BLI_listbase_count_ex(&tmp_bmain->object, 2) != 1) {
+ if (BLI_listbase_count_at_most(&tmp_bmain->object, 2) != 1) {
BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode");
BKE_main_free(tmp_bmain);
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 0dbe526117c..ebf2b63bb49 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1229,7 +1229,10 @@ void ED_curve_editnurb_make(Object *obedit)
if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
+ /* TODO(campbell): undo_system: investigate why this was needed. */
+#if 0
undo_editmode_clear();
+#endif
}
if (editnurb) {
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index cc8e272d4f7..b23f0f967ec 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -52,7 +52,7 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_view3d.h"
#include "ED_curve.h"
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index f8f96eb3bc9..4ced6ce506c 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -30,18 +30,29 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_util.h"
#include "ED_curve.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
#include "curve_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct {
ListBase nubase;
int actvert;
@@ -49,13 +60,18 @@ typedef struct {
ListBase fcurves, drivers;
int actnu;
int flag;
+
+ /* Stored in the object, needed since users may change the active key while in edit-mode. */
+ struct {
+ short shapenr;
+ } obedit;
+
+ size_t undo_size;
} UndoCurve;
-static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
+static void undocurve_to_editcurve(UndoCurve *ucu, Curve *cu, short *r_shapenr)
{
- Curve *cu = cu_v;
- UndoCurve *undoCurve = ucu;
- ListBase *undobase = &undoCurve->nubase;
+ ListBase *undobase = &ucu->nubase;
ListBase *editbase = BKE_curve_editNurbs_get(cu);
Nurb *nu, *newnu;
EditNurb *editnurb = cu->editnurb;
@@ -63,19 +79,19 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
BKE_nurbList_free(editbase);
- if (undoCurve->undoIndex) {
+ if (ucu->undoIndex) {
BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
- editnurb->keyindex = ED_curve_keyindex_hash_duplicate(undoCurve->undoIndex);
+ editnurb->keyindex = ED_curve_keyindex_hash_duplicate(ucu->undoIndex);
}
if (ad) {
if (ad->action) {
free_fcurves(&ad->action->curves);
- copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
+ copy_fcurves(&ad->action->curves, &ucu->fcurves);
}
free_fcurves(&ad->drivers);
- copy_fcurves(&ad->drivers, &undoCurve->drivers);
+ copy_fcurves(&ad->drivers, &ucu->drivers);
}
/* copy */
@@ -89,75 +105,152 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
BLI_addtail(editbase, newnu);
}
- cu->actvert = undoCurve->actvert;
- cu->actnu = undoCurve->actnu;
- cu->flag = undoCurve->flag;
+ cu->actvert = ucu->actvert;
+ cu->actnu = ucu->actnu;
+ cu->flag = ucu->flag;
+ *r_shapenr = ucu->obedit.shapenr;
ED_curve_updateAnimPaths(cu);
}
-static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
+static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr)
{
- Curve *cu = cu_v;
+ BLI_assert(BLI_array_is_zeroed(ucu, 1));
ListBase *nubase = BKE_curve_editNurbs_get(cu);
- UndoCurve *undoCurve;
EditNurb *editnurb = cu->editnurb, tmpEditnurb;
Nurb *nu, *newnu;
AnimData *ad = BKE_animdata_from_id(&cu->id);
- undoCurve = MEM_callocN(sizeof(UndoCurve), "undoCurve");
+ /* TODO: include size of fcurve & undoIndex */
+ // ucu->undo_size = 0;
if (editnurb->keyindex) {
- undoCurve->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex);
- tmpEditnurb.keyindex = undoCurve->undoIndex;
+ ucu->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex);
+ tmpEditnurb.keyindex = ucu->undoIndex;
}
if (ad) {
if (ad->action)
- copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
+ copy_fcurves(&ucu->fcurves, &ad->action->curves);
- copy_fcurves(&undoCurve->drivers, &ad->drivers);
+ copy_fcurves(&ucu->drivers, &ad->drivers);
}
/* copy */
for (nu = nubase->first; nu; nu = nu->next) {
newnu = BKE_nurb_duplicate(nu);
- if (undoCurve->undoIndex) {
+ if (ucu->undoIndex) {
ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu);
}
- BLI_addtail(&undoCurve->nubase, newnu);
+ BLI_addtail(&ucu->nubase, newnu);
+
+ ucu->undo_size += (
+ (nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) +
+ (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) +
+ (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) +
+ (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) +
+ sizeof(Nurb));
}
- undoCurve->actvert = cu->actvert;
- undoCurve->actnu = cu->actnu;
- undoCurve->flag = cu->flag;
+ ucu->actvert = cu->actvert;
+ ucu->actnu = cu->actnu;
+ ucu->flag = cu->flag;
- return undoCurve;
+ ucu->obedit.shapenr = shapenr;
}
-static void free_undoCurve(void *ucv)
+static void undocurve_free_data(UndoCurve *uc)
{
- UndoCurve *undoCurve = ucv;
+ BKE_nurbList_free(&uc->nubase);
- BKE_nurbList_free(&undoCurve->nubase);
+ BKE_curve_editNurb_keyIndex_free(&uc->undoIndex);
- BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
+ free_fcurves(&uc->fcurves);
+ free_fcurves(&uc->drivers);
+}
- free_fcurves(&undoCurve->fcurves);
- free_fcurves(&undoCurve->drivers);
+static Object *editcurve_object_from_context(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && ELEM(obedit->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = obedit->data;
+ if (BKE_curve_editNurbs_get(cu) != NULL) {
+ return obedit;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
- MEM_freeN(undoCurve);
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct CurveUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoCurve data;
+} CurveUndoStep;
+
+static bool curve_undosys_poll(bContext *C)
+{
+ Object *obedit = editcurve_object_from_context(C);
+ return (obedit != NULL);
}
-static void *get_data(bContext *C)
+static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- Object *obedit = CTX_data_edit_object(C);
- return obedit;
+ CurveUndoStep *us = (CurveUndoStep *)us_p;
+ us->obedit_ref.ptr = editcurve_object_from_context(C);
+ undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data, us->obedit_ref.ptr->shapenr);
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(curve_undosys_poll(C));
+
+ CurveUndoStep *us = (CurveUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ undocurve_to_editcurve(&us->data, obedit->data, &obedit->shapenr);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void curve_undosys_step_free(UndoStep *us_p)
+{
+ CurveUndoStep *us = (CurveUndoStep *)us_p;
+ undocurve_free_data(&us->data);
}
-/* and this is all the undo system needs to know */
-void undo_push_curve(bContext *C, const char *name)
+static void curve_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
- undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
+ CurveUndoStep *us = (CurveUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
}
+
+/* Export for ED_undo_sys. */
+void ED_curve_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit Curve";
+ ut->poll = curve_undosys_poll;
+ ut->step_encode = curve_undosys_step_encode;
+ ut->step_decode = curve_undosys_step_decode;
+ ut->step_free = curve_undosys_step_free;
+
+ ut->step_foreach_ID_ref = curve_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(CurveUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index a61f863b61e..3a76d0333f9 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -29,6 +29,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_array_utils.h"
+
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
@@ -36,10 +38,16 @@
#include "BKE_context.h"
#include "BKE_font.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_curve.h"
#include "ED_util.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
#define USE_ARRAY_STORE
#ifdef USE_ARRAY_STORE
@@ -50,6 +58,10 @@
# define ARRAY_CHUNK_SIZE 32
#endif
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoFont {
wchar_t *textbuf;
struct CharInfo *textbufinfo;
@@ -62,6 +74,8 @@ typedef struct UndoFont {
BArrayState *textbufinfo;
} store;
#endif
+
+ size_t undo_size;
} UndoFont;
@@ -202,23 +216,20 @@ static void uf_arraystore_free(UndoFont *uf)
BLI_array_store_at_size_clear(&uf_arraystore.bs_stride);
}
-
}
/** \} */
#endif /* USE_ARRAY_STORE */
-static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata))
+static void undofont_to_editfont(UndoFont *uf, Curve *cu)
{
- Curve *cu = (Curve *)ecu;
EditFont *ef = cu->editfont;
- const UndoFont *uf = uf_v;
size_t final_size;
#ifdef USE_ARRAY_STORE
- uf_arraystore_expand(uf_v);
+ uf_arraystore_expand(uf);
#endif
final_size = sizeof(wchar_t) * (uf->len + 1);
@@ -233,16 +244,17 @@ static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata))
ef->selstart = ef->selend = 0;
#ifdef USE_ARRAY_STORE
- uf_arraystore_expand_clear(uf_v);
+ uf_arraystore_expand_clear(uf);
#endif
}
-static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
+static void *undofont_from_editfont(UndoFont *uf, Curve *cu)
{
- Curve *cu = (Curve *)ecu;
+ BLI_assert(BLI_array_is_zeroed(uf, 1));
+
EditFont *ef = cu->editfont;
- UndoFont *uf = MEM_callocN(sizeof(*uf), __func__);
+ size_t mem_used_prev = MEM_get_memory_in_use();
size_t final_size;
@@ -269,13 +281,15 @@ static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
}
#endif
+ size_t mem_used_curr = MEM_get_memory_in_use();
+
+ uf->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(UndoFont);
+
return uf;
}
-static void free_undoFont(void *uf_v)
+static void undofont_free_data(UndoFont *uf)
{
- UndoFont *uf = uf_v;
-
#ifdef USE_ARRAY_STORE
{
LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data));
@@ -291,21 +305,91 @@ static void free_undoFont(void *uf_v)
if (uf->textbufinfo) {
MEM_freeN(uf->textbufinfo);
}
-
- MEM_freeN(uf);
}
-static void *get_undoFont(bContext *C)
+static Object *editfont_object_from_context(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (obedit && obedit->type == OB_FONT) {
- return obedit->data;
+ Curve *cu = obedit->data;
+ EditFont *ef = cu->editfont;
+ if (ef != NULL) {
+ return obedit;
+ }
}
return NULL;
}
-/* and this is all the undo system needs to know */
-void undo_push_font(bContext *C, const char *name)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct FontUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoFont data;
+} FontUndoStep;
+
+static bool font_undosys_poll(bContext *C)
+{
+ return editfont_object_from_context(C) != NULL;
+}
+
+static bool font_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ FontUndoStep *us = (FontUndoStep *)us_p;
+ us->obedit_ref.ptr = editfont_object_from_context(C);
+ Curve *cu = us->obedit_ref.ptr->data;
+ undofont_from_editfont(&us->data, cu);
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void font_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(font_undosys_poll(C));
+
+ FontUndoStep *us = (FontUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ Curve *cu = obedit->data;
+ undofont_to_editfont(&us->data, cu);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void font_undosys_step_free(UndoStep *us_p)
+{
+ FontUndoStep *us = (FontUndoStep *)us_p;
+ undofont_free_data(&us->data);
+}
+
+static void font_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+ FontUndoStep *us = (FontUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
}
+
+/* Export for ED_undo_sys. */
+void ED_font_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit Font";
+ ut->poll = font_undosys_poll;
+ ut->step_encode = font_undosys_step_encode;
+ ut->step_decode = font_undosys_step_decode;
+ ut->step_free = font_undosys_step_free;
+
+ ut->step_foreach_ID_ref = font_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(FontUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index bb3800941ab..5fe16226421 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -54,7 +54,6 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 5bd5c9c74b9..9d183222c2d 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -53,7 +53,6 @@
#include "DNA_gpencil_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_object.h"
@@ -1063,7 +1062,7 @@ static int gp_brush_remove_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, ts, brush))
return OPERATOR_CANCELLED;
- if (BLI_listbase_count_ex(&ts->gp_brushes, 2) < 2) {
+ if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) {
BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one");
return OPERATOR_CANCELLED;
}
@@ -1421,7 +1420,7 @@ static int gp_palette_remove_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, gpd, palette))
return OPERATOR_CANCELLED;
- if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) {
+ if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) {
BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 726215255aa..bc54bd89958 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -55,7 +55,6 @@
#include "DNA_gpencil_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index f54356dfed3..84b3ddccf77 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -46,7 +46,6 @@
#include "PIL_time.h"
-#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 7a9ad2b32c0..202d7630ae0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -45,7 +45,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_main.h"
#include "ED_gpencil.h"
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 91c9a36c31f..ae54dd802ee 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -49,6 +49,7 @@ struct Scene;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
+struct UndoType;
typedef struct EditBone {
struct EditBone *next, *prev;
@@ -139,7 +140,7 @@ bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend,
int join_armature_exec(struct bContext *C, struct wmOperator *op);
struct Bone *get_indexed_bone(struct Object *ob, int index);
float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only);
-EditBone *ED_armature_bone_find_name(const ListBase *edbo, const char *name);
+EditBone *ED_armature_bone_find_name(const struct ListBase *edbo, const char *name);
EditBone *ED_armature_bone_get_mirrored(const struct ListBase *edbo, EditBone *ebo);
void ED_armature_sync_selection(struct ListBase *edbo);
void ED_armature_validate_active(struct bArmature *arm);
@@ -178,8 +179,6 @@ void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers);
-void undo_push_armature(struct bContext *C, const char *name);
-
/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const EditBone *ebone);
void ED_armature_ebone_selectflag_set(EditBone *ebone, int flag);
@@ -187,14 +186,19 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select);
void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag);
void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
+/* editarmature_undo.c */
+void ED_armature_undosys_type(struct UndoType *ut);
+
/* armature_utils.c */
void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
void ED_armature_ebone_listbase_free(struct ListBase *lb);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src);
/* poseobject.c */
-void ED_armature_exit_posemode(struct bContext *C, struct Base *base);
-void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
+bool ED_object_posemode_exit_ex(struct Object *ob);
+bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
+bool ED_object_posemode_enter_ex(struct Object *ob);
+bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index d45e52d4c5a..da726cb8000 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -41,6 +41,7 @@ struct Curve;
struct EditNurb;
struct BezTriple;
struct BPoint;
+struct UndoType;
/* curve_ops.c */
void ED_operatortypes_curve(void);
@@ -48,7 +49,7 @@ void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
-ListBase *object_editcurve_get(struct Object *ob);
+struct ListBase *object_editcurve_get(struct Object *ob);
void ED_curve_editnurb_load(struct Object *obedit);
void ED_curve_editnurb_make(struct Object *obedit);
@@ -72,7 +73,7 @@ void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
/* editcurve_undo.c */
-void undo_push_curve(struct bContext *C, const char *name);
+void ED_curve_undosys_type(struct UndoType *ut);
/* editfont.c */
void ED_curve_editfont_load(struct Object *obedit);
@@ -91,7 +92,8 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]);
bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
/* editfont_undo.c */
-void undo_push_font(struct bContext *C, const char *name);
+void ED_font_undosys_type(struct UndoType *ut);
+
#if 0
/* debug only */
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index b652fb4c00b..b30929f5307 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -31,6 +31,8 @@
#define __ED_LATTICE_H__
struct wmKeyConfig;
+struct UndoType;
+struct Object;
/* lattice_ops.c */
void ED_operatortypes_lattice(void);
@@ -41,6 +43,6 @@ void ED_lattice_flags_set(struct Object *obedit, int flag);
bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
/* editlattice_undo.c */
-void undo_push_lattice(struct bContext *C, const char *name);
+void ED_lattice_undosys_type(struct UndoType *ut);
#endif /* __ED_LATTICE_H__ */
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 232d7d1d234..9982c87a764 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -34,6 +34,7 @@
struct bContext;
struct Object;
struct wmKeyConfig;
+struct UndoType;
void ED_operatortypes_metaball(void);
void ED_operatormacros_metaball(void);
@@ -47,6 +48,7 @@ void ED_mball_editmball_free(struct Object *obedit);
void ED_mball_editmball_make(struct Object *obedit);
void ED_mball_editmball_load(struct Object *obedit);
-void undo_push_mball(struct bContext *C, const char *name);
+/* editmball_undo.c */
+void ED_mball_undosys_type(struct UndoType *ut);
#endif /* __ED_MBALL_H__ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 40d796aeed1..349a1944a23 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -62,6 +62,7 @@ struct UvMapVert;
struct ToolSettings;
struct Object;
struct rcti;
+struct UndoType;
/* editmesh_utils.c */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis,
@@ -98,8 +99,6 @@ void EDBM_selectmode_flush(struct BMEditMesh *em);
void EDBM_deselect_flush(struct BMEditMesh *em);
void EDBM_select_flush(struct BMEditMesh *em);
-void undo_push_mesh(struct bContext *C, const char *name);
-
bool EDBM_vert_color_check(struct BMEditMesh *em);
void EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
@@ -130,6 +129,9 @@ void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
+/* editmesh_undo.c */
+void ED_mesh_undosys_type(struct UndoType *ut);
+
/* editmesh_select.c */
void EDBM_select_mirrored(
struct BMEditMesh *em, const int axis, const bool extend,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 5b2fdf29dd5..11dde2f5913 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -112,11 +112,12 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st
void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
/* bitflags for enter/exit editmode */
-#define EM_FREEDATA 1
-#define EM_FREEUNDO 2
-#define EM_WAITCURSOR 4
-#define EM_DO_UNDO 8
-#define EM_IGNORE_LAYER 16
+enum {
+ EM_FREEDATA = (1 << 0),
+ EM_WAITCURSOR = (1 << 1),
+ EM_DO_UNDO = (1 << 2),
+ EM_IGNORE_LAYER = (1 << 3),
+};
void ED_object_editmode_exit_ex(struct bContext *C, struct Scene *scene, struct Object *obedit, int flag);
void ED_object_editmode_exit(struct bContext *C, int flag);
void ED_object_editmode_enter(struct bContext *C, int flag);
@@ -196,6 +197,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Objec
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports);
void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
+void ED_object_mode_set(struct bContext *C, eObjectMode mode);
/* object_modifier.c */
enum {
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 79aa0a3a5ed..246419d64aa 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -28,31 +28,16 @@
struct bContext;
struct wmKeyConfig;
struct wmOperator;
+struct ImBuf;
+struct Image;
+struct UndoStep;
+struct UndoType;
/* paint_ops.c */
void ED_operatortypes_paint(void);
void ED_operatormacros_paint(void);
void ED_keymap_paint(struct wmKeyConfig *keyconf);
-/* paint_undo.c */
-enum {
- UNDO_PAINT_IMAGE = 0,
- UNDO_PAINT_MESH = 1,
-};
-
-typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
-typedef void (*UndoFreeCb)(struct ListBase *lb);
-typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
-
-int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
-void ED_undo_paint_step_num(struct bContext *C, int type, int num);
-const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active);
-void ED_undo_paint_free(void);
-bool ED_undo_paint_is_valid(int type, const char *name);
-bool ED_undo_paint_empty(int type);
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
-void ED_undo_paint_push_end(int type);
-
/* paint_image.c */
void ED_imapaint_clear_partial_redraw(void);
void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
@@ -61,6 +46,14 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperat
/* paint_image_undo.c */
void ED_image_undo_push_begin(const char *name);
void ED_image_undo_push_end(void);
-void ED_image_undo_restore(void);
+void ED_image_undo_restore(struct UndoStep *us);
+
+void ED_image_undosys_type(struct UndoType *ut);
+
+/* paint_curve_undo.c */
+void ED_paintcurve_undo_push_begin(const char *name);
+void ED_paintcurve_undo_push_end(void);
+
+void ED_paintcurve_undosys_type(struct UndoType *ut);
#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 6cb8c0cfb19..4f6aa1cc702 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -38,6 +38,7 @@ struct ParticleEditSettings;
struct rcti;
struct PTCacheEdit;
struct Scene;
+struct UndoType;
/* particle edit mode */
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
@@ -61,14 +62,8 @@ int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float
int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select);
void PE_deselect_all_visible(struct PTCacheEdit *edit);
-/* undo */
-void PE_undo_push(struct Scene *scene, const char *str);
-void PE_undo_step(struct Scene *scene, int step);
-void PE_undo(struct Scene *scene);
-void PE_redo(struct Scene *scene);
-bool PE_undo_is_valid(struct Scene *scene);
-void PE_undo_number(struct Scene *scene, int nr);
-const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active);
+/* particle_edit_undo.c */
+void ED_particle_undosys_type(struct UndoType *ut);
#endif /* __ED_PARTICLE_H__ */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 6daaac5bb42..7c17e7b68c3 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -36,6 +36,9 @@ struct Object;
struct RegionView3D;
struct ViewContext;
struct rcti;
+struct UndoStep;
+struct UndoType;
+struct ListBase;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
@@ -43,4 +46,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar,
struct RegionView3D *rv3d, struct Object *ob);
int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend);
+/* sculpt_undo.c */
+void ED_sculpt_undosys_type(struct UndoType *ut);
+
#endif /* __ED_SCULPT_H__ */
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index 5df7d9cfaef..763fbe3bac5 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -30,12 +30,16 @@
#ifndef __ED_TEXT_H__
#define __ED_TEXT_H__
-struct bContext;
struct SpaceText;
struct ARegion;
+struct UndoType;
+struct TextUndoBuf;
-void ED_text_undo_step(struct bContext *C, int step);
bool ED_text_region_location_from_cursor(struct SpaceText *st, struct ARegion *ar, const int cursor_co[2], int r_pixel_co[2]);
-#endif /* __ED_TEXT_H__ */
+/* text_undo.c */
+void ED_text_undosys_type(struct UndoType *ut);
+
+struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C);
+#endif /* __ED_TEXT_H__ */
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
new file mode 100644
index 00000000000..b3814ab5899
--- /dev/null
+++ b/source/blender/editors/include/ED_undo.h
@@ -0,0 +1,64 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_undo.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_UNDO_H__
+#define __ED_UNDO_H__
+
+struct bContext;
+struct wmOperator;
+struct wmOperatorType;
+struct UndoStack;
+
+/* 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);
+void ED_OT_undo(struct wmOperatorType *ot);
+void ED_OT_undo_push(struct wmOperatorType *ot);
+void ED_OT_redo(struct wmOperatorType *ot);
+void ED_OT_undo_redo(struct wmOperatorType *ot);
+void ED_OT_undo_history(struct wmOperatorType *ot);
+
+int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
+/* convenience since UI callbacks use this mostly*/
+void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
+void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
+
+bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
+
+struct UndoStack *ED_undo_stack_get(void);
+
+/* undo_system_types.c */
+void ED_undosys_type_init(void);
+void ED_undosys_type_free(void);
+
+/* memfile_undo.c */
+struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack);
+
+#endif /* __ED_UNDO_H__ */
+
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 60c4b3593aa..2653585dacc 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -32,9 +32,10 @@
#define __ED_UTIL_H__
struct bContext;
-struct SpaceLink;
-struct wmOperator;
struct wmOperatorType;
+struct ScrArea;
+struct SpaceLink;
+struct PackedFile;
/* ed_util.c */
@@ -47,40 +48,6 @@ void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct I
void ED_OT_flush_edits(struct wmOperatorType *ot);
-/* ************** Undo ************************ */
-
-/* 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);
-void ED_OT_undo(struct wmOperatorType *ot);
-void ED_OT_undo_push(struct wmOperatorType *ot);
-void ED_OT_redo(struct wmOperatorType *ot);
-void ED_OT_undo_redo(struct wmOperatorType *ot);
-void ED_OT_undo_history(struct wmOperatorType *ot);
-
-int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
-/* convenience since UI callbacks use this mostly*/
-void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
-void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
-
-bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
-
-/* undo_editmode.c */
-void undo_editmode_push(struct bContext *C, const char *name,
- void * (*getdata)(struct bContext *C),
- void (*freedata)(void *),
- void (*to_editmode)(void *, void *, void *),
- void *(*from_editmode)(void *, void *),
- int (*validate_undo)(void *, void *));
-
-
-void undo_editmode_clear(void);
-
/* ************** XXX OLD CRUFT WARNING ************* */
void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index bf39a8d353f..9f7cd62227c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -74,7 +74,7 @@
#include "BKE_paint.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_keyframing.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 7cf8a315895..046bb114a62 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -611,7 +611,8 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
if (str) {
- BKE_text_write(txt, str);
+ TextUndoBuf *utxt = NULL; // FIXME
+ BKE_text_write(txt, utxt, str);
MEM_freeN(str);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 15053f0d8ca..4714efdb4a7 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -303,19 +303,36 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
static void ui_block_region_draw(const bContext *C, ARegion *ar)
{
+ ScrArea *ctx_area = CTX_wm_area(C);
+ ARegion *ctx_region = CTX_wm_region(C);
uiBlock *block;
if (ar->do_draw & RGN_DRAW_REFRESH_UI) {
+ ScrArea *handle_ctx_area;
+ ARegion *handle_ctx_region;
uiBlock *block_next;
+
ar->do_draw &= ~RGN_DRAW_REFRESH_UI;
for (block = ar->uiblocks.first; block; block = block_next) {
block_next = block->next;
if (block->handle->can_refresh) {
+ handle_ctx_area = block->handle->ctx_area;
+ handle_ctx_region = block->handle->ctx_region;
+
+ if (handle_ctx_area) {
+ CTX_wm_area_set((bContext *)C, handle_ctx_area);
+ }
+ if (handle_ctx_region) {
+ CTX_wm_region_set((bContext *)C, handle_ctx_region);
+ }
ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
}
}
}
+ CTX_wm_area_set((bContext *)C, ctx_area);
+ CTX_wm_region_set((bContext *)C, ctx_region);
+
for (block = ar->uiblocks.first; block; block = block->next)
UI_block_draw(C, block);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 82a502db0ad..b92216138fd 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -75,7 +75,7 @@
#include "ED_screen.h"
#include "ED_object.h"
#include "ED_render.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 975bbddd893..eb79d0bec13 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -33,7 +33,6 @@
#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index e6c9b924c7f..42c19c6bc65 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -145,7 +145,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_animations = RNA_boolean_get(op->ptr, "include_animations");
sample_animations = RNA_boolean_get(op->ptr, "sample_animations");
- sampling_rate = (sample_animations)? RNA_int_get(op->ptr, "sampling_rate") : 0;
+ sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0;
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
@@ -496,8 +496,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
import_settings.min_chain_length = min_chain_length;
import_settings.keep_bind_info = keep_bind_info != 0;
- if (collada_import(C, &import_settings) )
- {
+ if (collada_import(C, &import_settings)) {
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index aa817928f92..7a7372f5a6a 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_array_utils.h"
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
@@ -41,31 +42,39 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_lattice.h"
#include "ED_util.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
#include "lattice_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoLattice {
BPoint *def;
int pntsu, pntsv, pntsw, actbp;
+ size_t undo_size;
} UndoLattice;
-static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata))
+static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt)
{
- UndoLattice *ult = (UndoLattice *)data;
- EditLatt *editlatt = (EditLatt *)edata;
- int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw;
+ int len = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw;
- memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint));
+ memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len);
editlatt->latt->actbp = ult->actbp;
}
-static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata))
+static void *undolatt_from_editlatt(UndoLattice *ult, EditLatt *editlatt)
{
- UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice");
- EditLatt *editlatt = (EditLatt *)edata;
+ BLI_assert(BLI_array_is_zeroed(ult, 1));
ult->def = MEM_dupallocN(editlatt->latt->def);
ult->pntsu = editlatt->latt->pntsu;
@@ -73,17 +82,19 @@ static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata))
ult->pntsw = editlatt->latt->pntsw;
ult->actbp = editlatt->latt->actbp;
+ ult->undo_size += sizeof(*ult->def) * ult->pntsu * ult->pntsv * ult->pntsw;
+
return ult;
}
-static void free_undoLatt(void *data)
+static void undolatt_free_data(UndoLattice *ult)
{
- UndoLattice *ult = (UndoLattice *)data;
-
- if (ult->def) MEM_freeN(ult->def);
- MEM_freeN(ult);
+ if (ult->def) {
+ MEM_freeN(ult->def);
+ }
}
+#if 0
static int validate_undoLatt(void *data, void *edata)
{
UndoLattice *ult = (UndoLattice *)data;
@@ -93,21 +104,92 @@ static int validate_undoLatt(void *data, void *edata)
ult->pntsv == editlatt->latt->pntsv &&
ult->pntsw == editlatt->latt->pntsw);
}
+#endif
-static void *get_editlatt(bContext *C)
+static Object *editlatt_object_from_context(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
-
if (obedit && obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
- return lt->editlatt;
+ if (lt->editlatt != NULL) {
+ return obedit;
+ }
}
return NULL;
}
-/* and this is all the undo system needs to know */
-void undo_push_lattice(bContext *C, const char *name)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct LatticeUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoLattice data;
+} LatticeUndoStep;
+
+static bool lattice_undosys_poll(bContext *C)
+{
+ return editlatt_object_from_context(C) != NULL;
+}
+
+static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
+ LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+ us->obedit_ref.ptr = editlatt_object_from_context(C);
+ Lattice *lt = us->obedit_ref.ptr->data;
+ undolatt_from_editlatt(&us->data, lt->editlatt);
+ us->step.data_size = us->data.undo_size;
+ return true;
}
+
+static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(lattice_undosys_poll(C));
+
+ LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ Lattice *lt = obedit->data;
+ EditLatt *editlatt = lt->editlatt;
+ undolatt_to_editlatt(&us->data, editlatt);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void lattice_undosys_step_free(UndoStep *us_p)
+{
+ LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+ undolatt_free_data(&us->data);
+}
+
+static void lattice_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+}
+
+/* Export for ED_undo_sys. */
+void ED_lattice_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit Lattice";
+ ut->poll = lattice_undosys_poll;
+ ut->step_encode = lattice_undosys_step_encode;
+ ut->step_decode = lattice_undosys_step_decode;
+ ut->step_free = lattice_undosys_step_free;
+
+ ut->step_foreach_ID_ref = lattice_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(LatticeUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/lattice/lattice_intern.h b/source/blender/editors/lattice/lattice_intern.h
index 94f528a0457..7902b992270 100644
--- a/source/blender/editors/lattice/lattice_intern.h
+++ b/source/blender/editors/lattice/lattice_intern.h
@@ -21,7 +21,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/metaball/lattice_intern.h
+/** \file blender/editors/lattice/lattice_intern.h
* \ingroup edlattice
*/
diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c
index 37a10cbe12a..d3d57a0b510 100644
--- a/source/blender/editors/lattice/lattice_ops.c
+++ b/source/blender/editors/lattice/lattice_ops.c
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/metaball/lattice_ops.c
+/** \file blender/editors/lattice/lattice_ops.c
* \ingroup edlattice
*/
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 2c98f05bd27..78bc361b222 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -36,8 +36,6 @@
#include "BLI_listbase.h"
#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 3ce9257de0c..874225e96a7 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -857,7 +857,7 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits)
{
Ref *r;
- if (BLI_listbase_count_ex(hits, 2) != 2)
+ if (BLI_listbase_count_at_most(hits, 2) != 2)
return;
for (r = hits->first; r->next; r = r->next) {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3a900cfdcae..ccb42e15aa6 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1125,7 +1125,7 @@ static bool bm_vert_connect_select_history(BMesh *bm)
* - Otherwise connect faces.
* - If all edges have been created already, closed the loop.
*/
- if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
+ if (BLI_listbase_count_at_most(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
BMEditSelection *ese;
int tot = 0;
bool changed = false;
@@ -3751,7 +3751,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
*
* note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each
* vert, but advantage of de-duplicating is minimal. */
- struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__);
+ struct SortPtrByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__);
LinkData *v_link;
for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) {
BMVert *v = v_link->data;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index dab6ecc9359..509cdb0e049 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -29,16 +29,24 @@
#include "DNA_key_types.h"
#include "BLI_listbase.h"
+#include "BLI_array_utils.h"
+#include "BLI_alloca.h"
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_util.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
#define USE_ARRAY_STORE
#ifdef USE_ARRAY_STORE
@@ -60,6 +68,9 @@
# include "BLI_task.h"
#endif
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
#ifdef USE_ARRAY_STORE
@@ -95,6 +106,8 @@ typedef struct UndoMesh {
BArrayState *mselect;
} store;
#endif /* USE_ARRAY_STORE */
+
+ size_t undo_size;
} UndoMesh;
@@ -474,23 +487,17 @@ static void um_arraystore_free(UndoMesh *um)
/* for callbacks */
/* undo simply makes copies of a bmesh */
-static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
{
-
+ BLI_assert(BLI_array_is_zeroed(um, 1));
#ifdef USE_ARRAY_STORE_THREAD
/* changes this waits is low, but must have finished */
if (um_arraystore.task_pool) {
BLI_task_pool_work_and_wait(um_arraystore.task_pool);
}
#endif
-
- BMEditMesh *em = emv;
- Mesh *obme = obdata;
-
- UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
-
/* make sure shape keys work */
- um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
+ um->me.key = key ? BKE_key_copy_nolib(key) : NULL;
/* BM_mesh_validate(em->bm); */ /* for troubleshooting */
@@ -536,13 +543,12 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
return um;
}
-static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
+static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh)
{
- BMEditMesh *em = em_v, *em_tmp;
+ BMEditMesh *em_tmp;
Object *ob = em->ob;
- UndoMesh *um = um_v;
BMesh *bm;
- Key *key = ((Mesh *) obdata)->key;
+ Key *key = obmesh->key;
#ifdef USE_ARRAY_STORE
#ifdef USE_ARRAY_STORE_THREAD
@@ -617,9 +623,8 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
#endif
}
-static void free_undo(void *um_v)
+static void undomesh_free_data(UndoMesh *um)
{
- UndoMesh *um = um_v;
Mesh *me = &um->me;
#ifdef USE_ARRAY_STORE
@@ -646,28 +651,165 @@ static void free_undo(void *um_v)
}
BKE_mesh_free(me);
- MEM_freeN(me);
}
-static void *getEditMesh(bContext *C)
+static Object *editmesh_object_from_context(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (obedit && obedit->type == OB_MESH) {
Mesh *me = obedit->data;
- return me->edit_btmesh;
+ if (me->edit_btmesh != NULL) {
+ return obedit;
+ }
}
return NULL;
}
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct MeshUndoStep {
+ UndoStep step;
+ /* Use for all ID lookups (can be NULL). */
+ struct UndoIDPtrMap *id_map;
+
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ /* Needed for MTexPoly's image use. */
+ UndoRefID_Object *image_array_ref;
+ UndoMesh data;
+} MeshUndoStep;
+
+static void mesh_undosys_step_encode_store_ids(MeshUndoStep *us)
{
- /* em->ob gets out of date and crashes on mesh undo,
- * this is an easy way to ensure its OK
- * though we could investigate the matter further. */
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- em->ob = obedit;
+ Mesh *me = us->obedit_ref.ptr->data;
+ BMesh *bm = me->edit_btmesh->bm;
+ const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ if (mtex_len != 0) {
+ ID **id_prev_array = BLI_array_alloca(id_prev_array, mtex_len);
+ memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len);
+
+ BMIter iter;
+ BMFace *efa;
+
+ if (us->id_map == NULL) {
+ us->id_map = BKE_undosys_ID_map_create();
+ }
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+ uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
+ uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
+ cd_poly_tex_offset < cd_poly_tex_offset_end;
+ cd_poly_tex_offset += sizeof(MTexPoly), i++)
+ {
+ const MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (tf->tpage != NULL) {
+ BKE_undosys_ID_map_add_with_prev(us->id_map, (ID *)tf->tpage, &id_prev_array[i]);
+ }
+ }
+ }
+ }
+}
+
+static void mesh_undosys_step_decode_restore_ids(MeshUndoStep *us)
+{
+ Mesh *me = us->obedit_ref.ptr->data;
+ BMesh *bm = me->edit_btmesh->bm;
+ const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ if (mtex_len != 0 && us->id_map) {
+ BMIter iter;
+ BMFace *efa;
+
+ ID *(*id_prev_array)[2] = BLI_array_alloca(id_prev_array, mtex_len);
+ memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len);
+
+ uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
+ uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
+ cd_poly_tex_offset < cd_poly_tex_offset_end;
+ cd_poly_tex_offset += sizeof(MTexPoly), i++)
+ {
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (tf->tpage != NULL) {
+ tf->tpage = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, (ID *)tf->tpage, id_prev_array[i]);
+ }
+ }
+ }
+ }
}
+
+static bool mesh_undosys_poll(bContext *C)
+{
+ return editmesh_object_from_context(C) != NULL;
+}
+
+static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ MeshUndoStep *us = (MeshUndoStep *)us_p;
+ us->obedit_ref.ptr = editmesh_object_from_context(C);
+ Mesh *me = us->obedit_ref.ptr->data;
+ undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key);
+ mesh_undosys_step_encode_store_ids(us);
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(mesh_undosys_poll(C));
+
+ MeshUndoStep *us = (MeshUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
+ undomesh_to_editmesh(&us->data, em, obedit->data);
+ mesh_undosys_step_decode_restore_ids(us);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void mesh_undosys_step_free(UndoStep *us_p)
+{
+ MeshUndoStep *us = (MeshUndoStep *)us_p;
+ undomesh_free_data(&us->data);
+
+ if (us->id_map != NULL) {
+ BKE_undosys_ID_map_destroy(us->id_map);
+ }
+}
+
+static void mesh_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ MeshUndoStep *us = (MeshUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+ if (us->id_map != NULL) {
+ BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
+ }
+}
+
+/* Export for ED_undo_sys. */
+void ED_mesh_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit Mesh";
+ ut->poll = mesh_undosys_poll;
+ ut->step_encode = mesh_undosys_step_encode;
+ ut->step_decode = mesh_undosys_step_decode;
+ ut->step_free = mesh_undosys_step_free;
+
+ ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(MeshUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 34b8d76db86..84374986b30 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -43,9 +43,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index 974bfb237d3..dc64f61a916 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -29,19 +29,31 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
+#include "BLI_array_utils.h"
#include "DNA_defs.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_mball.h"
#include "ED_util.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoMBall {
ListBase editelems;
int lastelem_index;
+ size_t undo_size;
} UndoMBall;
/* free all MetaElems from ListBase */
@@ -58,11 +70,8 @@ static void freeMetaElemlist(ListBase *lb)
}
}
-static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata))
+static void undomball_to_editmball(UndoMBall *umb, MetaBall *mb)
{
- MetaBall *mb = mb_v;
- UndoMBall *umb = umb_v;
-
freeMetaElemlist(mb->editelems);
mb->lastelem = NULL;
@@ -75,18 +84,15 @@ static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata)
mb->lastelem = ml_edit;
}
}
-
}
-static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata))
+static void *editmball_from_undomball(UndoMBall *umb, MetaBall *mb)
{
- MetaBall *mb = mb_v;
- UndoMBall *umb;
+ BLI_assert(BLI_array_is_zeroed(umb, 1));
/* allocate memory for undo ListBase */
- umb = MEM_callocN(sizeof(UndoMBall), __func__);
umb->lastelem_index = -1;
-
+
/* copy contents of current ListBase to the undo ListBase */
int index = 0;
for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
@@ -95,37 +101,99 @@ static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata))
if (ml_edit == mb->lastelem) {
umb->lastelem_index = index;
}
+ umb->undo_size += sizeof(MetaElem);
}
-
+
return umb;
}
/* free undo ListBase of MetaElems */
-static void free_undoMball(void *umb_v)
+static void undomball_free_data(UndoMBall *umb)
{
- UndoMBall *umb = umb_v;
-
freeMetaElemlist(&umb->editelems);
- MEM_freeN(umb);
}
-static MetaBall *metaball_get_obdata(Object *ob)
+static Object *editmball_object_from_context(bContext *C)
{
- if (ob && ob->type == OB_MBALL) {
- return ob->data;
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MBALL) {
+ MetaBall *mb = obedit->data;
+ if (mb->editelems != NULL) {
+ return obedit;
+ }
}
return NULL;
}
+/** \} */
-static void *get_data(bContext *C)
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct MBallUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoMBall data;
+} MBallUndoStep;
+
+static bool mball_undosys_poll(bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- return metaball_get_obdata(obedit);
+ return editmball_object_from_context(C) != NULL;
}
-/* this is undo system for MetaBalls */
-void undo_push_mball(bContext *C, const char *name)
+static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
+ MBallUndoStep *us = (MBallUndoStep *)us_p;
+ us->obedit_ref.ptr = editmball_object_from_context(C);
+ MetaBall *mb = us->obedit_ref.ptr->data;
+ editmball_from_undomball(&us->data, mb);
+ us->step.data_size = us->data.undo_size;
+ return true;
}
+
+static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ ED_object_mode_set(C, OB_MODE_EDIT);
+
+ MBallUndoStep *us = (MBallUndoStep *)us_p;
+ Object *obedit = us->obedit_ref.ptr;
+ MetaBall *mb = obedit->data;
+ undomball_to_editmball(&us->data, mb);
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+}
+
+static void mball_undosys_step_free(UndoStep *us_p)
+{
+ MBallUndoStep *us = (MBallUndoStep *)us_p;
+ undomball_free_data(&us->data);
+}
+
+static void mball_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ MBallUndoStep *us = (MBallUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+}
+
+/* Export for ED_undo_sys. */
+void ED_mball_undosys_type(UndoType *ut)
+{
+ ut->name = "Edit MBall";
+ ut->poll = mball_undosys_poll;
+ ut->step_encode = mball_undosys_step_encode;
+ ut->step_decode = mball_undosys_step_decode;
+ ut->step_free = mball_undosys_step_free;
+
+ ut->step_foreach_ID_ref = mball_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(MBallUndoStep);
+
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 0b486f8e5a3..c6820c83f95 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -413,7 +413,7 @@ Object *ED_object_add_type(
/* for as long scene has editmode... */
if (CTX_data_edit_object(C))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
/* deselects all, sets scene->basact */
ob = BKE_object_add(bmain, scene, type, name);
@@ -1573,7 +1573,7 @@ static void curvetomesh(Main *bmain, Scene *scene, Object *ob)
BKE_mesh_from_nurbs(ob); /* also does users */
if (ob->type == OB_MESH) {
- BKE_object_free_modifiers(ob);
+ BKE_object_free_modifiers(ob, 0);
/* Game engine defaults for mesh objects */
ob->body_type = OB_BODY_TYPE_STATIC;
@@ -1702,7 +1702,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* When 2 objects with linked data are selected, converting both
* would keep modifiers on all but the converted object [#26003] */
if (ob->type == OB_MESH) {
- BKE_object_free_modifiers(ob); /* after derivedmesh calls! */
+ BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
}
}
}
@@ -1727,7 +1727,7 @@ static int convert_exec(bContext *C, wmOperator *op)
BKE_mesh_to_curve(scene, newob);
if (newob->type == OB_CURVE) {
- BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
+ BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
ED_rigidbody_object_remove(bmain, scene, newob);
}
}
@@ -1760,7 +1760,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* re-tessellation is called by DM_to_mesh */
- BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
+ BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
}
else if (ob->type == OB_FONT) {
ob->flag |= OB_DONE;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f67ecbce1d0..844ed168157 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -85,6 +85,7 @@
#include "BKE_editlattice.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
+#include "BKE_undo_system.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -93,7 +94,7 @@
#include "ED_lattice.h"
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_image.h"
#include "RNA_access.h"
@@ -657,7 +658,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
if (!is_mode_set)
ED_object_editmode_enter(C, EM_WAITCURSOR);
else
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene);
@@ -702,7 +703,7 @@ static int posemode_exec(bContext *C, wmOperator *op)
Base *base = CTX_data_active_base(C);
Object *ob = base->object;
const int mode_flag = OB_MODE_POSE;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ bool is_mode_set = (ob->mode & mode_flag) != 0;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
@@ -713,12 +714,15 @@ static int posemode_exec(bContext *C, wmOperator *op)
if (ob->type == OB_ARMATURE) {
if (ob == CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
- ED_armature_enter_posemode(C, base);
+ is_mode_set = false;
+ }
+
+ if (is_mode_set) {
+ ED_object_posemode_exit(C, ob);
+ }
+ else {
+ ED_object_posemode_enter(C, ob);
}
- else if (is_mode_set)
- ED_armature_exit_posemode(C, base);
- else
- ED_armature_enter_posemode(C, base);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index fda342f8a4d..d70a69e30f8 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -136,3 +136,43 @@ void ED_object_mode_toggle(bContext *C, eObjectMode mode)
}
}
}
+
+/* Wrapper for operator */
+void ED_object_mode_set(bContext *C, eObjectMode mode)
+{
+#if 0
+ wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
+ PointerRNA ptr;
+
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_enum_set(&ptr, "mode", mode);
+ RNA_boolean_set(&ptr, "toggle", false);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+#else
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return;
+ }
+ if (ob->mode == mode) {
+ /* pass */
+ }
+ else if (mode != OB_MODE_OBJECT) {
+ if (ob && (ob->mode & mode) == 0) {
+ /* needed so we don't do undo pushes. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->op_undo_depth++;
+ ED_object_mode_toggle(C, mode);
+ wm->op_undo_depth--;
+ }
+ }
+ else {
+ /* needed so we don't do undo pushes. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->op_undo_depth++;
+ ED_object_mode_toggle(C, ob->mode);
+ wm->op_undo_depth--;
+
+ }
+#endif
+}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 93bfd156707..bdffaf31384 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -126,8 +126,6 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
if (edit==0) return;
- PTCacheUndo_clear(edit);
-
if (edit->points) {
LOOP_POINTS {
if (point->keys)
@@ -4379,9 +4377,6 @@ void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, Partic
if (psys && !cache)
recalc_emitter_field(ob, psys);
PE_update_object(scene, ob, 1);
-
- PTCacheUndo_clear(edit);
- PE_undo_push(scene, "Original");
}
}
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 288e59a8671..ef0a2711fdd 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -38,47 +38,37 @@
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
+#include "BKE_context.h"
+#include "BKE_undo_system.h"
+#include "ED_object.h"
#include "ED_particle.h"
+#include "ED_physics.h"
#include "particle_edit_utildefines.h"
#include "physics_intern.h"
-static void free_PTCacheUndo(PTCacheUndo *undo)
-{
- PTCacheEditPoint *point;
- int i;
-
- for (i=0, point=undo->points; i<undo->totpoint; i++, point++) {
- if (undo->particles && (undo->particles + i)->hair)
- MEM_freeN((undo->particles + i)->hair);
- if (point->keys)
- MEM_freeN(point->keys);
- }
- if (undo->points)
- MEM_freeN(undo->points);
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
- if (undo->particles)
- MEM_freeN(undo->particles);
-
- BKE_ptcache_free_mem(&undo->mem_cache);
-}
-
-static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
+static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
{
PTCacheEditPoint *point;
int i;
+ size_t mem_used_prev = MEM_get_memory_in_use();
+
undo->totpoint= edit->totpoint;
if (edit->psys) {
@@ -86,8 +76,9 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
pa= undo->particles= MEM_dupallocN(edit->psys->particles);
- for (i=0; i<edit->totpoint; i++, pa++)
+ for (i=0; i<edit->totpoint; i++, pa++) {
pa->hair= MEM_dupallocN(pa->hair);
+ }
undo->psys_flag = edit->psys->flag;
}
@@ -98,8 +89,9 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
pm = undo->mem_cache.first;
for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++)
+ for (i=0; i<BPHYS_TOT_DATA; i++) {
pm->data[i] = MEM_dupallocN(pm->data[i]);
+ }
}
}
@@ -110,9 +102,13 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
point->keys= MEM_dupallocN(point->keys);
/* no need to update edit key->co & key->time pointers here */
}
+
+ size_t mem_used_curr = MEM_get_memory_in_use();
+
+ undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo);
}
-static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
+static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleData *pa;
@@ -120,16 +116,20 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
POINT_P; KEY_K;
LOOP_POINTS {
- if (psys && psys->particles[p].hair)
+ if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
+ }
- if (point->keys)
+ if (point->keys) {
MEM_freeN(point->keys);
+ }
}
- if (psys && psys->particles)
+ if (psys && psys->particles) {
MEM_freeN(psys->particles);
- if (edit->points)
+ }
+ if (edit->points) {
MEM_freeN(edit->points);
+ }
if (edit->mirror_cache) {
MEM_freeN(edit->mirror_cache);
edit->mirror_cache= NULL;
@@ -171,9 +171,9 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
pm = edit->pid.cache->mem_cache.first;
for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++)
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
pm->data[i] = MEM_dupallocN(pm->data[i]);
-
+ }
BKE_ptcache_mem_pointers_init(pm);
LOOP_POINTS {
@@ -191,150 +191,107 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
}
}
-void PE_undo_push(Scene *scene, const char *str)
+static void undoptcache_free_data(PTCacheUndo *undo)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
- PTCacheUndo *undo;
- int nr;
-
- if (!edit) return;
-
- /* remove all undos after (also when curundo==NULL) */
- while (edit->undo.last != edit->curundo) {
- undo= edit->undo.last;
- BLI_remlink(&edit->undo, undo);
- free_PTCacheUndo(undo);
- MEM_freeN(undo);
- }
+ PTCacheEditPoint *point;
+ int i;
- /* make new */
- edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
- BLI_strncpy(undo->name, str, sizeof(undo->name));
- BLI_addtail(&edit->undo, undo);
-
- /* and limit amount to the maximum */
- nr= 0;
- undo= edit->undo.last;
- while (undo) {
- nr++;
- if (nr==U.undosteps) break;
- undo= undo->prev;
- }
- if (undo) {
- while (edit->undo.first != undo) {
- PTCacheUndo *first= edit->undo.first;
- BLI_remlink(&edit->undo, first);
- free_PTCacheUndo(first);
- MEM_freeN(first);
+ for (i = 0, point=undo->points; i < undo->totpoint; i++, point++) {
+ if (undo->particles && (undo->particles + i)->hair) {
+ MEM_freeN((undo->particles + i)->hair);
+ }
+ if (point->keys) {
+ MEM_freeN(point->keys);
}
}
-
- /* copy */
- make_PTCacheUndo(edit, edit->curundo);
+ if (undo->points) {
+ MEM_freeN(undo->points);
+ }
+ if (undo->particles) {
+ MEM_freeN(undo->particles);
+ }
+ BKE_ptcache_free_mem(&undo->mem_cache);
}
-void PE_undo_step(Scene *scene, int step)
-{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+/** \} */
- if (!edit) return;
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
- if (step==0) {
- get_PTCacheUndo(edit, edit->curundo);
- }
- else if (step==1) {
-
- if (edit->curundo==NULL || edit->curundo->prev==NULL) {
- /* pass */
- }
- else {
- if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
- edit->curundo= edit->curundo->prev;
- get_PTCacheUndo(edit, edit->curundo);
- }
- }
- else {
- /* curundo has to remain current situation! */
-
- if (edit->curundo==NULL || edit->curundo->next==NULL) {
- /* pass */
- }
- else {
- get_PTCacheUndo(edit, edit->curundo->next);
- edit->curundo= edit->curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
- }
- }
+typedef struct ParticleUndoStep {
+ UndoStep step;
+ UndoRefID_Scene scene_ref;
+ UndoRefID_Object object_ref;
+ PTCacheUndo data;
+} ParticleUndoStep;
- DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
+static bool particle_undosys_poll(struct bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = OBACT;
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ return (edit != NULL);
}
-bool PE_undo_is_valid(Scene *scene)
+static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
-
- if (edit) {
- return (edit->undo.last != edit->undo.first);
- }
- return 0;
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ us->scene_ref.ptr = CTX_data_scene(C);
+ us->object_ref.ptr = us->scene_ref.ptr->basact->object;
+ PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+ undoptcache_from_editcache(&us->data, edit);
+ return true;
}
-void PTCacheUndo_clear(PTCacheEdit *edit)
+static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
- PTCacheUndo *undo;
-
- if (edit==NULL) return;
-
- undo= edit->undo.first;
- while (undo) {
- free_PTCacheUndo(undo);
- undo= undo->next;
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
+ BLI_assert(particle_undosys_poll(C));
+
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ Scene *scene = us->scene_ref.ptr;
+ Object *ob = us->object_ref.ptr;
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ if (edit) {
+ undoptcache_to_editcache(&us->data, edit);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ BLI_assert(0);
}
- BLI_freelistN(&edit->undo);
- edit->curundo= NULL;
}
-void PE_undo(Scene *scene)
+static void particle_undosys_step_free(UndoStep *us_p)
{
- PE_undo_step(scene, 1);
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ undoptcache_free_data(&us->data);
}
-void PE_redo(Scene *scene)
+static void particle_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
- PE_undo_step(scene, -1);
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
}
-void PE_undo_number(Scene *scene, int nr)
+/* Export for ED_undo_sys. */
+void ED_particle_undosys_type(UndoType *ut)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
- PTCacheUndo *undo;
- int a=0;
-
- for (undo= edit->undo.first; undo; undo= undo->next, a++) {
- if (a==nr) break;
- }
- edit->curundo= undo;
- PE_undo_step(scene, 0);
-}
+ ut->name = "Edit Particle";
+ ut->poll = particle_undosys_poll;
+ ut->step_encode = particle_undosys_step_encode;
+ ut->step_decode = particle_undosys_step_decode;
+ ut->step_free = particle_undosys_step_free;
+ ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
-/* get name of undo item, return null if no item with this index */
-/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
-{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
- PTCacheUndo *undo;
-
- if (r_active) *r_active = false;
-
- if (edit) {
- undo= BLI_findlink(&edit->undo, nr);
- if (undo) {
- if (r_active && (undo == edit->curundo)) {
- *r_active = true;
- }
- return undo->name;
- }
- }
- return NULL;
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ParticleUndoStep);
}
+
+/** \} */
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index d85720f956c..53a70abca05 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -911,10 +911,7 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P
edit->emitter_field = NULL;
edit->emitter_cosnos = NULL;
-
- BLI_listbase_clear(&edit->undo);
- edit->curundo = NULL;
-
+
edit->points = MEM_dupallocN(edit_from->points);
pa = psys->particles;
LOOP_POINTS {
@@ -943,9 +940,6 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P
recalc_lengths(edit);
recalc_emitter_field(ob, psys);
PE_update_object(scene, ob, true);
-
- PTCacheUndo_clear(edit);
- PE_undo_push(scene, "Original");
}
static void remove_particle_systems_from_object(Object *ob_to)
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 2f95f360fe2..ce1e9d5cf6a 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -48,8 +48,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_fluidsim.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -67,6 +65,8 @@
/* enable/disable overall compilation */
#ifdef WITH_MOD_FLUID
+#include "BKE_global.h"
+
#include "WM_api.h"
#include "DNA_scene_types.h"
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index cb281936634..f3f3697caaa 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -68,7 +68,6 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
-void PTCacheUndo_clear(struct PTCacheEdit *edit);
void PE_create_particle_edit(struct Scene *scene, struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
void recalc_lengths(struct PTCacheEdit *edit);
void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 1bfc162a331..412f9acf718 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -39,7 +39,6 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index fa80fb5fbc1..b7083c29721 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -44,7 +44,6 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index c27570aabc5..509fdcf080a 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -65,6 +65,7 @@
#include "BKE_sequencer.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_undo_system.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -73,6 +74,7 @@
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_view3d.h"
#include "RE_pipeline.h"
@@ -88,6 +90,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "BLO_undofile.h"
#include "render_intern.h"
@@ -624,7 +627,7 @@ static void render_image_restore_layer(RenderJob *rj)
/* For single layer renders keep the active layer
* visible, or show the compositing result. */
RenderResult *rr = RE_AcquireResultRead(rj->re);
- if(RE_HasCombinedLayer(rr)) {
+ if (RE_HasCombinedLayer(rr)) {
sima->iuser.layer = 0;
}
RE_ReleaseResult(rj->re);
@@ -866,7 +869,8 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get main */
if (G.debug_value == 101) {
/* thread-safety experiment, copy main from the undo buffer */
- mainp = BKE_undo_get_main(&scene);
+ struct MemFile *memfile = ED_undosys_stack_memfile_get_active(CTX_wm_manager(C)->undo_stack);
+ mainp = BLO_memfile_main_get(memfile, CTX_data_main(C), &scene);
}
else
mainp = CTX_data_main(C);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index fc0922c7b7c..a53a16906d3 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -63,6 +63,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -1938,15 +1939,29 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* before setting the view */
if (vertical) {
/* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
- if (v2d->cur.ymax < - 0.001f)
- y = min_ii(y, v2d->cur.ymin);
-
+ if (v2d->cur.ymax < -FLT_EPSILON) {
+ /* Clamp to lower view boundary */
+ if (v2d->tot.ymin < -v2d->winy) {
+ y = min_ii(y, 0);
+ }
+ else {
+ y = min_ii(y, v2d->cur.ymin);
+ }
+ }
+
y = -y;
}
else {
/* don't jump back when panels close or hide */
- if (!is_context_new)
- x = max_ii(x, v2d->cur.xmax);
+ if (!is_context_new) {
+ if (v2d->tot.xmax > v2d->winx) {
+ x = max_ii(x, 0);
+ }
+ else {
+ x = max_ii(x, v2d->cur.xmax);
+ }
+ }
+
y = -y;
}
@@ -2138,7 +2153,7 @@ static const char *meta_data_list[] =
BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset)
{
- return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]);
+ return (IMB_metadata_get_field(ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]);
}
static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top)
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index c365f8c5fcc..437d82bdc77 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -75,6 +75,7 @@
#include "ED_screen_types.h"
#include "ED_sequencer.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_view3d.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index adead9a8b9e..9527dc4fe83 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -51,7 +51,6 @@ set(SRC
paint_mask.c
paint_ops.c
paint_stroke.c
- paint_undo.c
paint_utils.c
paint_vertex.c
paint_vertex_color_ops.c
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 8d9812f41d9..120514762f4 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -40,6 +40,7 @@
#include "BKE_paint.h"
#include "ED_view3d.h"
+#include "ED_paint.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -203,7 +204,7 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
}
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
add_index = pc->add_index;
@@ -241,6 +242,8 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
pcp[add_index].bez.h1 = HD_ALIGN;
}
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
}
@@ -302,7 +305,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
#define DELETE_TAG 2
@@ -342,6 +345,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
#undef DELETE_TAG
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
return OPERATOR_FINISHED;
@@ -379,7 +384,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
if (!pc)
return false;
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
if (toggle) {
PaintCurvePoint *pcp;
@@ -444,10 +449,14 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
}
}
- if (!pcp)
+ if (!pcp) {
+ ED_paintcurve_undo_push_end();
return false;
+ }
}
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
return true;
@@ -562,9 +571,6 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
psd->align = align;
op->customdata = psd;
- if (do_select)
- ED_paintcurve_undo_push(C, op, pc);
-
/* first, clear all selection from points */
for (i = 0; i < pc->tot_points; i++)
pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
@@ -587,6 +593,8 @@ static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *ev
if (event->type == psd->event && event->val == KM_RELEASE) {
MEM_freeN(psd);
+ ED_paintcurve_undo_push_begin(op->type->name);
+ ED_paintcurve_undo_push_end();
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index 70f92999864..77f06180df6 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -30,100 +30,139 @@
#include "DNA_space_types.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_undo_system.h"
#include "ED_paint.h"
+#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
#include "paint_intern.h"
-typedef struct UndoCurve {
- struct UndoImageTile *next, *prev;
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+typedef struct UndoCurve {
PaintCurvePoint *points; /* points of curve */
int tot_points;
- int active_point;
-
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ int add_index;
} UndoCurve;
-static void paintcurve_undo_restore(bContext *C, ListBase *lb)
+static void undocurve_from_paintcurve(UndoCurve *uc, const PaintCurve *pc)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- UndoCurve *uc;
- PaintCurve *pc = NULL;
+ BLI_assert(BLI_array_is_zeroed(uc, 1));
+ uc->points = MEM_dupallocN(pc->points);
+ uc->tot_points = pc->tot_points;
+ uc->add_index = pc->add_index;
+}
- if (p->brush) {
- pc = p->brush->paint_curve;
- }
+static void undocurve_to_paintcurve(const UndoCurve *uc, PaintCurve *pc)
+{
+ MEM_SAFE_FREE(pc->points);
+ pc->points = MEM_dupallocN(uc->points);
+ pc->tot_points = uc->tot_points;
+ pc->add_index = uc->add_index;
+}
- if (!pc) {
- return;
- }
+static void undocurve_free_data(UndoCurve *uc)
+{
+ MEM_SAFE_FREE(uc->points);
+}
- uc = (UndoCurve *)lb->first;
+/** \} */
- if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) {
- SWAP(PaintCurvePoint *, pc->points, uc->points);
- SWAP(int, pc->tot_points, uc->tot_points);
- SWAP(int, pc->add_index, uc->active_point);
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
-static void paintcurve_undo_delete(ListBase *lb)
+typedef struct PaintCurveUndoStep {
+ UndoStep step;
+ PaintCurve *pc;
+ UndoCurve data;
+} PaintCurveUndoStep;
+
+static bool paintcurve_undosys_poll(bContext *C)
{
- UndoCurve *uc;
- uc = (UndoCurve *)lb->first;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ return (p->brush && p->brush->paint_curve);
+}
- if (uc->points)
- MEM_freeN(uc->points);
- uc->points = NULL;
+static void paintcurve_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
+{
+ /* XXX, use to set the undo type only. */
+ UNUSED_VARS(C, us_p);
}
-/**
- * \note This is called before executing steps (not after).
- */
-void ED_paintcurve_undo_push(bContext *C, wmOperator *op, PaintCurve *pc)
+static bool paintcurve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- ListBase *lb = NULL;
- int undo_stack_id;
- UndoCurve *uc;
-
- switch (mode) {
- case ePaintTexture2D:
- case ePaintTextureProjective:
- undo_stack_id = UNDO_PAINT_IMAGE;
- break;
-
- case ePaintSculpt:
- undo_stack_id = UNDO_PAINT_MESH;
- break;
-
- default:
- /* do nothing, undo is handled by global */
- return;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL;
+ if (pc == NULL) {
+ return false;
}
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ BLI_assert(us->step.data_size == 0);
- ED_undo_paint_push_begin(undo_stack_id, op->type->name,
- paintcurve_undo_restore, paintcurve_undo_delete, NULL);
- lb = undo_paint_push_get_list(undo_stack_id);
+ us->pc = pc;
+ undocurve_from_paintcurve(&us->data, pc);
- uc = MEM_callocN(sizeof(*uc), "Undo_curve");
+ return true;
+}
- lb->first = uc;
+static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir))
+{
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_to_paintcurve(&us->data, us->pc);
+}
- BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname));
- uc->tot_points = pc->tot_points;
- uc->active_point = pc->add_index;
- uc->points = MEM_dupallocN(pc->points);
+static void paintcurve_undosys_step_free(UndoStep *us_p)
+{
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_free_data(&us->data);
+}
+
+/* Export for ED_undo_sys. */
+void ED_paintcurve_undosys_type(UndoType *ut)
+{
+ ut->name = "Paint Curve";
+ /* don't poll for now */
+ ut->poll = paintcurve_undosys_poll;
+ ut->step_encode_init = paintcurve_undosys_step_encode_init;
+ ut->step_encode = paintcurve_undosys_step_encode;
+ ut->step_decode = paintcurve_undosys_step_decode;
+ ut->step_free = paintcurve_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = false;
+
+ ut->step_size = sizeof(PaintCurveUndoStep);
+}
+
+/** \} */
- undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points);
- ED_undo_paint_push_end(undo_stack_id);
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+void ED_paintcurve_undo_push_begin(const char *name)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE);
}
+
+void ED_paintcurve_undo_push_end(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index c6472b258ca..cb6dba4772f 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -58,6 +58,8 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -145,9 +147,11 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -491,7 +495,8 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
- ED_image_undo_restore();
+ UndoStack *ustack = CTX_wm_manager(C)->undo_stack;
+ ED_image_undo_restore(ustack->step_init);
}
if (pop->mode == PAINT_MODE_3D_PROJECT) {
@@ -1174,14 +1179,17 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = sima->image;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
+
ED_image_undo_push_begin(op->type->name);
paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
DAG_id_tag_update(&ima->id, 0);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 894277402a7..c1dd31ea055 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1035,6 +1035,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
ImBuf tmpbuf;
IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
@@ -1043,9 +1045,9 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
if (s->canvas->rect_float)
- tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
else
- tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
IMB_rectblend(s->canvas, &tmpbuf, frombuf, mask,
curveb, texmaskb, mask_max,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 60fe8555ba2..e5bddae971d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1499,15 +1499,16 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
if (generate_tile) {
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
volatile void *undorect;
if (tinf->masked) {
undorect = image_undo_push_tile(
- pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
}
else {
undorect = image_undo_push_tile(
- pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
tx, ty, NULL, &pjIma->valid[tile_index], true, false);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
index b5b64eb3e16..ef28dafa8c9 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -29,6 +29,10 @@
#include "BLI_threads.h"
#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -37,17 +41,22 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "ED_paint.h"
+#include "ED_undo.h"
#include "GPU_draw.h"
#include "paint_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
char ibufname[IMB_FILENAME_SIZE];
union {
@@ -64,6 +73,8 @@ typedef struct UndoImageTile {
short source, use_float;
char gen_type;
bool valid;
+
+ size_t undo_size;
} UndoImageTile;
/* this is a static resource for non-globality,
@@ -129,16 +140,17 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop
}
}
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
+void *image_undo_find_tile(
+ ListBase *undo_tiles,
+ Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
short use_float = ibuf->rect_float ? 1 : 0;
- for (tile = lb->first; tile; tile = tile->next) {
+ for (tile = undo_tiles->first; tile; tile = tile->next) {
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
if (tile->use_float == use_float) {
- if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) {
+ if (STREQ(tile->ibufname, ibuf->name)) {
if (mask) {
/* allocate mask if requested */
if (!tile->mask) {
@@ -161,10 +173,10 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
}
void *image_undo_push_tile(
+ ListBase *undo_tiles,
Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile,
unsigned short **mask, bool **valid, bool proj, bool find_prev)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
int allocsize;
short use_float = ibuf->rect_float ? 1 : 0;
@@ -174,7 +186,7 @@ void *image_undo_push_tile(
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
if (find_prev) {
- data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
+ data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
if (data) {
return data;
}
@@ -185,7 +197,6 @@ void *image_undo_push_tile(
}
tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname));
tile->x = x_tile;
tile->y = y_tile;
@@ -214,8 +225,7 @@ void *image_undo_push_tile(
if (proj) {
BLI_spin_lock(&undolock);
}
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
- BLI_addtail(lb, tile);
+ BLI_addtail(undo_tiles, tile);
if (proj) {
BLI_spin_unlock(&undolock);
@@ -225,10 +235,10 @@ void *image_undo_push_tile(
void image_undo_remove_masks(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
UndoImageTile *tile;
- for (tile = lb->first; tile; tile = tile->next) {
+ for (tile = undo_tiles->first; tile; tile = tile->next) {
if (tile->mask) {
MEM_freeN(tile->mask);
tile->mask = NULL;
@@ -265,28 +275,19 @@ static void image_undo_restore_runtime(ListBase *lb)
IMB_freeImBuf(tmpibuf);
}
-static void image_undo_restore_list(bContext *C, ListBase *lb)
+static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map)
{
- Main *bmain = CTX_data_main(C);
- Image *ima = NULL;
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
+ ImBuf *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
- IB_rectfloat | IB_rect);
+ /* Store last found image. */
+ ID *image_prev[2] = {NULL};
- for (tile = lb->first; tile; tile = tile->next) {
+ for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
short use_float;
- /* find image based on name, pointer becomes invalid with global undo */
- if (ima && STREQ(tile->idname, ima->id.name)) {
- /* ima is valid */
- }
- else {
- ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name));
- }
+ Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev);
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
/* current ImBuf filename was changed, probably current frame
@@ -346,50 +347,187 @@ static void image_undo_free_list(ListBase *lb)
void ED_image_undo_push_begin(const char *name)
{
- ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, name, image_undo_restore_list, image_undo_free_list, NULL);
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
}
void ED_image_undo_push_end(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+}
+
+static void image_undo_invalidate(void)
+{
UndoImageTile *tile;
- int deallocsize = 0;
+ ListBase *lb = ED_image_undo_get_tiles();
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ tile->valid = false;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+ ListBase tiles;
+
+ /* Use for all ID lookups (can be NULL). */
+ struct UndoIDPtrMap *id_map;
+} ImageUndoStep;
+
+static void image_undosys_step_encode_store_ids(ImageUndoStep *us)
+{
+ us->id_map = BKE_undosys_ID_map_create();
+
+ ID *image_prev = NULL;
+ for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
+ BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev);
+ }
+}
+
+/* Restore at runtime. */
+#if 0
+static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us)
+{
+ ID *image_prev[2] = {NULL};
+ for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
+ tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev);
+ }
+}
+#endif
+
+static bool image_undosys_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ BLI_listbase_clear(&us->tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init. */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
/* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (tile = lb->first; tile;) {
+ for (UndoImageTile *tile = us->tiles.first; tile;) {
if (!tile->valid) {
UndoImageTile *tmp_tile = tile->next;
- deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
MEM_freeN(tile->rect.pt);
- BLI_freelinkN(lb, tile);
+ BLI_freelinkN(&us->tiles, tile);
tile = tmp_tile;
}
else {
+ us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
tile = tile->next;
}
}
- /* don't forget to remove the size of deallocated tiles */
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+ image_undosys_step_encode_store_ids(us);
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ return true;
}
-static void image_undo_invalidate(void)
+static void image_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir))
{
- UndoImageTile *tile;
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+#if 0
+ paint_undosys_step_decode_restore_ids(us);
+#endif
+ image_undo_restore_list(&us->tiles, us->id_map);
+}
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
+static void image_undosys_step_free(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_free_list(&us->tiles);
+ BKE_undosys_ID_map_destroy(us->id_map);
+}
+
+static void image_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (us->id_map != NULL) {
+ BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
}
}
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ return &us->tiles;
+}
+
+ListBase *ED_image_undo_get_tiles(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ return ED_image_undosys_step_get_tiles(us);
+}
+
/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(void)
+void ED_image_undo_restore(UndoStep *us)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ListBase *lb = ED_image_undosys_step_get_tiles(us);
image_undo_restore_runtime(lb);
image_undo_invalidate();
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 52be4be4c0d..63a12b3c145 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -55,6 +55,7 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
struct DMCoNo;
+struct UndoStep;
enum ePaintMode;
/* paint_stroke.c */
@@ -221,15 +222,20 @@ void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* paint_image_undo.c */
void *image_undo_find_tile(
+ ListBase *undo_tiles,
struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile,
unsigned short **mask, bool validate);
void *image_undo_push_tile(
+ ListBase *undo_tiles,
struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile,
unsigned short **, bool **valid, bool proj, bool find_prev);
void image_undo_remove_masks(void);
void image_undo_init_locks(void);
void image_undo_end_locks(void);
+struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
+struct ListBase *ED_image_undo_get_tiles(void);
+
/* sculpt_uv.c */
int uv_sculpt_poll(struct bContext *C);
int uv_sculpt_keymap_poll(struct bContext *C);
@@ -304,10 +310,6 @@ typedef enum {
void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop,
RCFlags flags);
-/* paint_undo.c */
-struct ListBase *undo_paint_push_get_list(int type);
-void undo_paint_push_count_alloc(int type, int size);
-
/* paint_hide.c */
typedef enum {
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
deleted file mode 100644
index 27d3f6648a2..00000000000
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * ***** 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.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/sculpt_paint/paint_undo.c
- * \ingroup edsculpt
- * \brief Undo system for painting and sculpting.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-#include "BLI_string.h"
-
-#include "DNA_userdef_types.h"
-
-#include "BKE_blender_undo.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
-
-#include "ED_paint.h"
-
-#include "paint_intern.h"
-
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- char name[BKE_UNDO_STR_MAX];
- uintptr_t undosize;
-
- ListBase elems;
-
- UndoRestoreCb restore;
- UndoFreeCb free;
- UndoCleanupCb cleanup;
-} UndoElem;
-
-typedef struct UndoStack {
- int type;
- ListBase elems;
- UndoElem *current;
-} UndoStack;
-
-static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
-static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
-
-/* Generic */
-
-static void undo_restore(bContext *C, UndoStack *UNUSED(stack), UndoElem *uel)
-{
- if (uel && uel->restore)
- uel->restore(C, &uel->elems);
-}
-
-static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel)
-{
- if (uel && uel->free) {
- uel->free(&uel->elems);
- BLI_freelistN(&uel->elems);
- }
-}
-
-static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
-{
- UndoElem *uel;
- int nr;
-
- /* Undo push is split up in begin and end, the reason is that as painting
- * happens more tiles/nodes are added to the list, and at the very end we
- * know how much memory the undo used to remove old undo elements */
-
- /* remove all undos after (also when stack->current==NULL) */
- while (stack->elems.last != stack->current) {
- uel = stack->elems.last;
- undo_elem_free(stack, uel);
- BLI_freelinkN(&stack->elems, uel);
- }
-
- /* make new */
- stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file");
- uel->restore = restore;
- uel->free = free;
- uel->cleanup = cleanup;
- BLI_addtail(&stack->elems, uel);
-
- /* name can be a dynamic string */
- BLI_strncpy(uel->name, name, sizeof(uel->name));
-
- /* limit amount to the maximum amount*/
- nr = 0;
- uel = stack->elems.last;
- while (uel) {
- nr++;
- if (nr == U.undosteps) break;
- uel = uel->prev;
- }
- if (uel) {
- while (stack->elems.first != uel) {
- UndoElem *first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- }
- }
-}
-
-static void undo_stack_push_end(UndoStack *stack)
-{
- UndoElem *uel;
- uintptr_t totmem, maxmem;
- int totundo = 0;
-
- /* first limit to undo steps */
- uel = stack->elems.last;
-
- while (uel) {
- totundo++;
- if (totundo > U.undosteps) break;
- uel = uel->prev;
- }
-
- if (uel) {
- UndoElem *first;
-
- /* in case the undo steps are zero, the current pointer will be invalid */
- if (uel == stack->current)
- stack->current = NULL;
-
- do {
- first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- } while (first != uel);
- }
-
- if (U.undomemory != 0) {
- /* limit to maximum memory (afterwards, we can't know in advance) */
- totmem = 0;
- maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024;
-
- uel = stack->elems.last;
- while (uel) {
- totmem += uel->undosize;
- if (totmem > maxmem) break;
- uel = uel->prev;
- }
-
- if (uel) {
- while (stack->elems.first != uel) {
- UndoElem *first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- }
- }
- }
-}
-
-static void undo_stack_cleanup(UndoStack *stack, bContext *C)
-{
- UndoElem *uel = stack->elems.first;
- bool stack_reset = false;
-
- while (uel) {
- if (uel->cleanup && uel->cleanup(C, &uel->elems)) {
- UndoElem *uel_tmp = uel->next;
- if (stack->current == uel) {
- stack->current = NULL;
- stack_reset = true;
- }
- undo_elem_free(stack, uel);
- BLI_freelinkN(&stack->elems, uel);
- uel = uel_tmp;
- }
- else
- uel = uel->next;
- }
- if (stack_reset) {
- stack->current = stack->elems.last;
- }
-
-}
-
-static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name)
-{
- UndoElem *undo;
-
- /* first cleanup any old undo steps that may belong to invalid data */
- undo_stack_cleanup(stack, C);
-
- if (step == 1) {
- if (stack->current == NULL) {
- /* pass */
- }
- else {
- if (!name || STREQ(stack->current->name, name)) {
- if (G.debug & G_DEBUG_WM) {
- printf("%s: undo '%s'\n", __func__, stack->current->name);
- }
- undo_restore(C, stack, stack->current);
- stack->current = stack->current->prev;
- return 1;
- }
- }
- }
- else if (step == -1) {
- if ((stack->current != NULL && stack->current->next == NULL) || BLI_listbase_is_empty(&stack->elems)) {
- /* pass */
- }
- else {
- if (!name || STREQ(stack->current->name, name)) {
- undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first;
- undo_restore(C, stack, undo);
- stack->current = undo;
- if (G.debug & G_DEBUG_WM) {
- printf("%s: redo %s\n", __func__, undo->name);
- }
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static void undo_stack_free(UndoStack *stack)
-{
- UndoElem *uel;
-
- for (uel = stack->elems.first; uel; uel = uel->next)
- undo_elem_free(stack, uel);
-
- BLI_freelistN(&stack->elems);
- stack->current = NULL;
-}
-
-/* Exported Functions */
-
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup);
- else if (type == UNDO_PAINT_MESH)
- undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup);
-}
-
-ListBase *undo_paint_push_get_list(int type)
-{
- if (type == UNDO_PAINT_IMAGE) {
- if (ImageUndoStack.current) {
- return &ImageUndoStack.current->elems;
- }
- }
- else if (type == UNDO_PAINT_MESH) {
- if (MeshUndoStack.current) {
- return &MeshUndoStack.current->elems;
- }
- }
-
- return NULL;
-}
-
-void undo_paint_push_count_alloc(int type, int size)
-{
- if (type == UNDO_PAINT_IMAGE)
- ImageUndoStack.current->undosize += size;
- else if (type == UNDO_PAINT_MESH)
- MeshUndoStack.current->undosize += size;
-}
-
-void ED_undo_paint_push_end(int type)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_end(&ImageUndoStack);
- else if (type == UNDO_PAINT_MESH)
- undo_stack_push_end(&MeshUndoStack);
-}
-
-int ED_undo_paint_step(bContext *C, int type, int step, const char *name)
-{
- if (type == UNDO_PAINT_IMAGE)
- return undo_stack_step(C, &ImageUndoStack, step, name);
- else if (type == UNDO_PAINT_MESH)
- return undo_stack_step(C, &MeshUndoStack, step, name);
-
- return 0;
-}
-
-static void undo_step_num(bContext *C, UndoStack *stack, int step)
-{
- UndoElem *uel;
- int a = 0;
- int curnum = BLI_findindex(&stack->elems, stack->current);
-
- for (uel = stack->elems.first; uel; uel = uel->next, a++) {
- if (a == step) break;
- }
-
- if (curnum > a) {
- while (a++ != curnum)
- undo_stack_step(C, stack, 1, NULL);
- }
- else if (curnum < a) {
- while (a-- != curnum)
- undo_stack_step(C, stack, -1, NULL);
- }
-}
-
-void ED_undo_paint_step_num(bContext *C, int type, int step)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_step_num(C, &ImageUndoStack, step);
- else if (type == UNDO_PAINT_MESH)
- undo_step_num(C, &MeshUndoStack, step);
-}
-
-static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active)
-{
- UndoElem *uel;
-
- if (r_active) *r_active = false;
-
- uel = BLI_findlink(&stack->elems, nr);
- if (uel) {
- if (r_active && (uel == stack->current)) {
- *r_active = true;
- }
- return uel->name;
- }
-
- return NULL;
-}
-
-const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active)
-{
-
- if (type == UNDO_PAINT_IMAGE) {
- undo_stack_cleanup(&ImageUndoStack, C);
- return undo_stack_get_name(&ImageUndoStack, nr, r_active);
- }
- else if (type == UNDO_PAINT_MESH) {
- undo_stack_cleanup(&MeshUndoStack, C);
- return undo_stack_get_name(&MeshUndoStack, nr, r_active);
- }
- return NULL;
-}
-
-bool ED_undo_paint_empty(int type)
-{
- UndoStack *stack;
-
- if (type == UNDO_PAINT_IMAGE)
- stack = &ImageUndoStack;
- else if (type == UNDO_PAINT_MESH)
- stack = &MeshUndoStack;
- else
- return true;
-
- if (stack->current == NULL) {
- return true;
- }
-
- return false;
-}
-
-bool ED_undo_paint_is_valid(int type, const char *name)
-{
- UndoStack *stack;
-
- if (type == UNDO_PAINT_IMAGE)
- stack = &ImageUndoStack;
- else if (type == UNDO_PAINT_MESH)
- stack = &MeshUndoStack;
- else
- return 0;
-
- if (stack->current == NULL) {
- /* pass */
- }
- else {
- if (name && STREQ(stack->current->name, name))
- return 1;
- else
- return stack->elems.first != stack->elems.last;
- }
- return 0;
-}
-
-void ED_undo_paint_free(void)
-{
- undo_stack_free(&ImageUndoStack);
- undo_stack_free(&MeshUndoStack);
-}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index ede1269e220..34e60187a73 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1563,7 +1563,7 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
/* logic for 3 or more is identical */
- const int vfcount = BM_vert_face_count_ex(v, 3);
+ const int vfcount = BM_vert_face_count_at_most(v, 3);
/* Don't modify corner vertices */
if (vfcount > 1) {
@@ -1578,7 +1578,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
const BMVert *v_other = adj_v[i];
- if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) {
+ if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
add_v3_v3(avg, v_other->co);
total++;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index cf1937f14d4..e46760258e1 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -122,6 +122,8 @@ typedef struct SculptUndoNode {
/* shape keys */
char shapeName[sizeof(((KeyBlock *)0))->name];
+
+ size_t undo_size;
} SculptUndoNode;
/* Factor of brush to have rake point following behind
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 794ac14483a..e90d2b58c0c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -48,6 +48,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -57,6 +59,7 @@
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
+#include "BKE_undo_system.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -64,12 +67,22 @@
#include "GPU_buffers.h"
#include "ED_paint.h"
+#include "ED_object.h"
+#include "ED_sculpt.h"
+#include "ED_undo.h"
#include "bmesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
-/************************** Undo *************************/
+
+typedef struct UndoSculpt {
+ ListBase nodes;
+
+ size_t undo_size;
+} UndoSculpt;
+
+static UndoSculpt *sculpt_undo_get_nodes(void);
static void update_cb(PBVHNode *node, void *rebuild)
{
@@ -454,7 +467,7 @@ static int sculpt_undo_bmesh_restore(bContext *C,
return false;
}
-static void sculpt_undo_restore(bContext *C, ListBase *lb)
+static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -574,7 +587,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
}
}
-static void sculpt_undo_free(ListBase *lb)
+static void sculpt_undo_free_list(ListBase *lb)
{
SculptUndoNode *unode;
int i;
@@ -617,6 +630,8 @@ static void sculpt_undo_free(ListBase *lb)
}
}
+/* Most likely we don't need this. */
+#if 0
static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
{
Object *ob = CTX_data_active_object(C);
@@ -633,16 +648,17 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
return false;
}
+#endif
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
- if (!lb) {
+ if (usculpt == NULL) {
return NULL;
}
- return BLI_findptr(lb, node, offsetof(SculptUndoNode, node));
+ return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
@@ -668,10 +684,11 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
}
}
-static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
- SculptUndoType type)
+static SculptUndoNode *sculpt_undo_alloc_node(
+ Object *ob, PBVHNode *node,
+ SculptUndoType type)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
SculptSession *ss = ob->sculpt;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
@@ -696,23 +713,23 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
/* general TODO, fix count_alloc */
switch (type) {
case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float) * 3 * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short) * 3 * allvert, "SculptUndoNode.no");
- undo_paint_push_count_alloc(UNDO_PAINT_MESH,
- (sizeof(float) * 3 +
- sizeof(short) * 3 +
- sizeof(int)) * allvert);
+ unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+
+ usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
break;
case SCULPT_UNDO_HIDDEN:
if (maxgrid)
sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
else
unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden");
-
+
break;
case SCULPT_UNDO_MASK:
unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
- undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert);
+
+ usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
+
break;
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
@@ -721,7 +738,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
break;
}
- BLI_addtail(lb, unode);
+ BLI_addtail(&usculpt->nodes, unode);
if (maxgrid) {
/* multires */
@@ -798,12 +815,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
PBVHNode *node,
SculptUndoType type)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
- SculptUndoNode *unode = lb->first;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
- if (!lb->first) {
+ SculptUndoNode *unode = usculpt->nodes.first;
+
+ if (unode == NULL) {
unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
@@ -842,7 +860,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
unode->bm_entry = BM_log_entry_add(ss->bm_log);
}
- BLI_addtail(lb, unode);
+ BLI_addtail(&usculpt->nodes, unode);
}
if (node) {
@@ -883,8 +901,9 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
return unode;
}
-SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
- SculptUndoType type)
+SculptUndoNode *sculpt_undo_push_node(
+ Object *ob, PBVHNode *node,
+ SculptUndoType type)
{
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
@@ -954,17 +973,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
void sculpt_undo_push_begin(const char *name)
{
- ED_undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup);
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
}
void sculpt_undo_push_end(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
/* we don't need normals in the undo stack */
- for (unode = lb->first; unode; unode = unode->next) {
+ for (unode = usculpt->nodes.first; unode; unode = unode->next) {
if (unode->no) {
MEM_freeN(unode->no);
unode->no = NULL;
@@ -974,7 +994,97 @@ void sculpt_undo_push_end(void)
BKE_pbvh_node_layer_disp_free(unode->node);
}
- ED_undo_paint_push_end(UNDO_PAINT_MESH);
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct SculptUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-sculpt-mode. */
+ UndoSculpt data;
+} SculptUndoStep;
+
+static bool sculpt_undosys_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->mode & OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ BLI_listbase_clear(&us->data.nodes);
+}
+
+static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'SculptUndoStep' added by encode_init. */
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void sculpt_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_SCULPT);
+ BLI_assert(sculpt_undosys_poll(C));
+
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ sculpt_undo_restore_list(C, &us->data.nodes);
+}
- WM_file_tag_modified();
+static void sculpt_undosys_step_free(UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ sculpt_undo_free_list(&us->data.nodes);
}
+
+/* Export for ED_undo_sys. */
+void ED_sculpt_undosys_type(UndoType *ut)
+{
+ ut->name = "Sculpt";
+ ut->poll = sculpt_undosys_poll;
+ ut->step_encode_init = sculpt_undosys_step_encode_init;
+ ut->step_encode = sculpt_undosys_step_encode;
+ ut->step_decode = sculpt_undosys_step_decode;
+ ut->step_free = sculpt_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(SculptUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ return &us->data;
+}
+
+static UndoSculpt *sculpt_undo_get_nodes(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT);
+ return sculpt_undosys_step_get_nodes(us);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
index bfc808f6d83..ba6cef38acd 100644
--- a/source/blender/editors/space_action/action_buttons.c
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -50,8 +50,6 @@
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
-#include "BKE_main.h"
-#include "BKE_global.h"
#include "BKE_screen.h"
#include "BKE_unit.h"
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index fbef14c07c4..f1153b5bed0 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -54,10 +54,8 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_key.h"
-#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 72b1245ca8a..1c15a7c5950 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -59,7 +59,6 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_key.h"
-#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index fc1b6877f5e..2a703ebb46c 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -51,7 +51,7 @@
#include "WM_types.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 3c48f3c1111..49bd0794a51 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -470,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
}
else {
/* set one user as active based on active index */
- if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1))
+ if (ct->index >= BLI_listbase_count_at_most(&ct->users, ct->index + 1))
ct->index = 0;
ct->user = BLI_findlink(&ct->users, ct->index);
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 1504ce1a7ba..d2a7244eded 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -49,7 +49,7 @@
#include "WM_api.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index 71a5a825b0e..8c5be7c9d04 100644
--- a/source/blender/editors/space_clip/tracking_ops_orient.c
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -42,7 +42,6 @@
#include "BKE_context.h"
#include "BKE_constraint.h"
#include "BKE_tracking.h"
-#include "BKE_global.h"
#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 52d01063175..396f3cf32f4 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -597,7 +597,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0;
- BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relpath));
+ BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath));
draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index df6bd01144d..1ada5538fe3 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -64,7 +64,7 @@
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index df6de83336d..530506e7c1d 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -686,7 +686,7 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) {
sgraph->ads->filter_grp = (Group *)new_id;
}
- if ((ID *)sgraph->ads->source == old_id) {
+ if (sgraph->ads && (ID *)sgraph->ads->source == old_id) {
sgraph->ads->source = new_id;
}
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 20f9658020d..c105f40f1d6 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -762,7 +762,7 @@ static void uiblock_layer_pass_buttons(
}
/* view */
- if (BLI_listbase_count_ex(&rr->views, 2) > 1 &&
+ if (BLI_listbase_count_at_most(&rr->views, 2) > 1 &&
((!show_stereo) || (!RE_RenderResult_is_stereo(rr))))
{
rview = BLI_findlink(&rr->views, iuser->view);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 9740a62d4f0..e14e7820403 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1851,7 +1851,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
/* we need renderresult for exr and rendered multiview */
scene = CTX_data_scene(C);
rr = BKE_image_acquire_renderresult(scene, ima);
- bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2;
+ bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 : BLI_listbase_count_at_most(&ima->views, 2) < 2;
bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr);
/* error handling */
@@ -2658,8 +2658,9 @@ static int image_invert_exec(bContext *C, wmOperator *op)
if (ibuf->mipmap[0])
ibuf->userflags |= IB_MIPMAP_INVALID;
- if (support_undo)
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ if (support_undo) {
+ ED_image_undo_push_end();
+ }
/* force GPU reupload, all image is invalid */
GPU_free_image(ima);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index e1a31be4afb..4dd3f369204 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -56,7 +56,7 @@
#include "BKE_main.h"
#include "BKE_sca.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 87b7599ec66..c86e9872c0a 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -1501,7 +1501,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) &&
- (BLI_listbase_count_ex(&mstrip->strips, 3) == 2))
+ (BLI_listbase_count_at_most(&mstrip->strips, 3) == 2))
{
/* remove this temp meta, so that we can see the strips inside */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 508a16926e6..173c919e38c 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -53,7 +53,7 @@
#include "ED_node.h" /* own include */
-#include "ED_util.h"
+#include "ED_undo.h"
/************************* Node Socket Manipulation **************************/
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 0b001ca9578..71edd855cf0 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -52,7 +52,6 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 12b9d273a47..27c96bd0232 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -54,7 +54,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -241,7 +241,7 @@ static eOLDrawState tree_element_set_active_object(
}
if (ob != scene->obedit)
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
return OL_DRAWSEL_NORMAL;
}
@@ -714,13 +714,16 @@ static eOLDrawState tree_element_active_pose(
}
if (set != OL_SETSEL_NONE) {
- if (scene->obedit)
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ if (scene->obedit) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+ }
- if (ob->mode & OB_MODE_POSE)
- ED_armature_exit_posemode(C, base);
- else
- ED_armature_enter_posemode(C, base);
+ if (ob->mode & OB_MODE_POSE) {
+ ED_object_posemode_exit(C, ob);
+ }
+ else {
+ ED_object_posemode_enter(C, ob);
+ }
}
else {
if (ob->mode & OB_MODE_POSE) {
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index cf9deeaedf8..e8275d597a6 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -68,7 +68,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -418,7 +418,7 @@ static void object_delete_cb(
// check also library later
if (scene->obedit == base->object)
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
/* leave for ED_outliner_id_unref to handle */
@@ -873,7 +873,7 @@ static void object_delete_hierarchy_cb(
/* Check also library later. */
for (; obedit && (obedit != base->object); obedit = obedit->parent);
if (obedit == base->object) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
}
outline_delete_hierarchy(C, reports, scene, base);
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index 39b48f5b52c..91420a5d63a 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -48,6 +48,7 @@ set(SRC
text_format_py.c
text_header.c
text_ops.c
+ text_undo.c
text_format.h
text_intern.h
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index da5fa9da046..9163831c333 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -241,7 +241,7 @@ static void get_suggest_prefix(Text *text, int offset)
texttool_suggest_prefix(line + i, len);
}
-static void confirm_suggestion(Text *text)
+static void confirm_suggestion(Text *text, TextUndoBuf *utxt)
{
SuggItem *sel;
int i, over = 0;
@@ -260,7 +260,7 @@ static void confirm_suggestion(Text *text)
// for (i = 0; i < skipleft; i++)
// txt_move_left(text, 0);
BLI_assert(memcmp(sel->name, &line[i], over) == 0);
- txt_insert_buf(text, sel->name + over);
+ txt_insert_buf(text, utxt, sel->name + over);
// for (i = 0; i < skipleft; i++)
// txt_move_right(text, 0);
@@ -284,7 +284,8 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent *
ED_area_tag_redraw(CTX_wm_area(C));
if (texttool_suggest_first() == texttool_suggest_last()) {
- confirm_suggestion(st->text);
+ TextUndoBuf *utxt = NULL; // FIXME
+ confirm_suggestion(st->text, utxt);
text_update_line_edited(st->text->curl);
text_autocomplete_free(C, op);
return OPERATOR_FINISHED;
@@ -314,6 +315,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
(void)text;
+ TextUndoBuf *utxt = NULL; // FIXME
+
if (st->doplugins && texttool_text_is_active(st->text)) {
if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
if (texttool_docs_get()) tools |= TOOL_DOCUMENT;
@@ -340,7 +343,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
case MIDDLEMOUSE:
if (event->val == KM_PRESS) {
if (text_do_suggest_select(st, ar)) {
- confirm_suggestion(st->text);
+ confirm_suggestion(st->text, utxt);
text_update_line_edited(st->text->curl);
swallow = 1;
}
@@ -375,7 +378,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
case PADENTER:
if (event->val == KM_PRESS) {
if (tools & TOOL_SUGG_LIST) {
- confirm_suggestion(st->text);
+ confirm_suggestion(st->text, utxt);
text_update_line_edited(st->text->curl);
swallow = 1;
draw = 1;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index f75cd129f67..223a3031f3b 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -731,7 +731,8 @@ static int text_paste_exec(bContext *C, wmOperator *op)
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
- txt_insert_buf(text, buf);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+ txt_insert_buf(text, utxt, buf);
text_update_edited(text);
MEM_freeN(buf);
@@ -756,7 +757,10 @@ void TEXT_OT_paste(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_paste_exec;
ot->poll = text_edit_poll;
-
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
/* properties */
RNA_def_boolean(ot->srna, "selection", 0, "Selection", "Paste text selected elsewhere rather than copied (X11 only)");
}
@@ -766,9 +770,11 @@ void TEXT_OT_paste(wmOperatorType *ot)
static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op))
{
Text *text = CTX_data_edit_text(C);
-
- txt_duplicate_line(text);
-
+
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
+ txt_duplicate_line(text, utxt);
+
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
/* run the script while editing, evil but useful */
@@ -785,10 +791,13 @@ void TEXT_OT_duplicate_line(wmOperatorType *ot)
ot->name = "Duplicate Line";
ot->idname = "TEXT_OT_duplicate_line";
ot->description = "Duplicate the current line";
-
+
/* api callbacks */
ot->exec = text_duplicate_line_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* copy operator *********************/
@@ -838,7 +847,9 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op))
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
txt_copy_clipboard(text);
- txt_delete_selected(text);
+
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+ txt_delete_selected(text, utxt);
text_update_cursor_moved(C);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
@@ -860,6 +871,9 @@ void TEXT_OT_cut(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_cut_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* indent operator *********************/
@@ -870,12 +884,15 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op))
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
if (txt_has_sel(text)) {
txt_order_cursors(text, false);
- txt_indent(text);
+ txt_indent(text, utxt);
+ }
+ else {
+ txt_add_char(text, utxt, '\t');
}
- else
- txt_add_char(text, '\t');
text_update_edited(text);
@@ -895,6 +912,9 @@ void TEXT_OT_indent(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_indent_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* unindent operator *********************/
@@ -905,8 +925,10 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op))
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
txt_order_cursors(text, false);
- txt_unindent(text);
+ txt_unindent(text, utxt);
text_update_edited(text);
@@ -926,6 +948,9 @@ void TEXT_OT_unindent(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_unindent_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* line break operator *********************/
@@ -941,14 +966,15 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op))
// double check tabs/spaces before splitting the line
curts = txt_setcurr_tab_spaces(text, space);
- txt_split_curline(text);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+ txt_split_curline(text, utxt);
for (a = 0; a < curts; a++) {
if (text->flags & TXT_TABSTOSPACES) {
- txt_add_char(text, ' ');
+ txt_add_char(text, utxt, ' ');
}
else {
- txt_add_char(text, '\t');
+ txt_add_char(text, utxt, '\t');
}
}
@@ -970,10 +996,13 @@ void TEXT_OT_line_break(wmOperatorType *ot)
ot->name = "Line Break";
ot->idname = "TEXT_OT_line_break";
ot->description = "Insert line break at cursor position";
-
+
/* api callbacks */
ot->exec = text_line_break_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* comment operator *********************/
@@ -985,8 +1014,10 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op))
if (txt_has_sel(text)) {
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
txt_order_cursors(text, false);
- txt_comment(text);
+ txt_comment(text, utxt);
text_update_edited(text);
text_update_cursor_moved(C);
@@ -1003,10 +1034,13 @@ void TEXT_OT_comment(wmOperatorType *ot)
ot->name = "Comment";
ot->idname = "TEXT_OT_comment";
ot->description = "Convert selected text to comment";
-
+
/* api callbacks */
ot->exec = text_comment_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* uncomment operator *********************/
@@ -1018,8 +1052,10 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op))
if (txt_has_sel(text)) {
text_drawcache_tag_update(CTX_wm_space_text(C), 0);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
txt_order_cursors(text, false);
- txt_uncomment(text);
+ txt_uncomment(text, utxt);
text_update_edited(text);
text_update_cursor_moved(C);
@@ -1041,6 +1077,9 @@ void TEXT_OT_uncomment(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_uncomment_exec;
ot->poll = text_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* convert whitespace operator *********************/
@@ -1174,6 +1213,9 @@ void TEXT_OT_convert_whitespace(wmOperatorType *ot)
ot->exec = text_convert_whitespace_exec;
ot->poll = text_edit_poll;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
/* properties */
RNA_def_enum(ot->srna, "type", whitespace_type_items, TO_SPACES, "Type", "Type of whitespace to convert to");
}
@@ -1265,8 +1307,10 @@ static int move_lines_exec(bContext *C, wmOperator *op)
{
Text *text = CTX_data_edit_text(C);
const int direction = RNA_enum_get(op->ptr, "direction");
-
- txt_move_lines(text, direction);
+
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
+ txt_move_lines(text, utxt, direction);
text_update_cursor_moved(C);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
@@ -1295,6 +1339,9 @@ void TEXT_OT_move_lines(wmOperatorType *ot)
ot->exec = move_lines_exec;
ot->poll = text_edit_poll;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
/* properties */
RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", "");
}
@@ -1936,6 +1983,7 @@ static int text_delete_exec(bContext *C, wmOperator *op)
Text *text = CTX_data_edit_text(C);
int type = RNA_enum_get(op->ptr, "type");
+
text_drawcache_tag_update(st, 0);
/* behavior could be changed here,
@@ -1945,11 +1993,13 @@ static int text_delete_exec(bContext *C, wmOperator *op)
else if (type == DEL_NEXT_WORD) type = DEL_NEXT_CHAR;
}
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
if (type == DEL_PREV_WORD) {
if (txt_cursor_is_line_start(text)) {
- txt_backspace_char(text);
+ txt_backspace_char(text, utxt);
}
- txt_backspace_word(text);
+ txt_backspace_word(text, utxt);
}
else if (type == DEL_PREV_CHAR) {
@@ -1965,13 +2015,13 @@ static int text_delete_exec(bContext *C, wmOperator *op)
}
}
- txt_backspace_char(text);
+ txt_backspace_char(text, utxt);
}
else if (type == DEL_NEXT_WORD) {
if (txt_cursor_is_line_end(text)) {
- txt_delete_char(text);
+ txt_delete_char(text, utxt);
}
- txt_delete_word(text);
+ txt_delete_word(text, utxt);
}
else if (type == DEL_NEXT_CHAR) {
@@ -1987,7 +2037,7 @@ static int text_delete_exec(bContext *C, wmOperator *op)
}
}
- txt_delete_char(text);
+ txt_delete_char(text, utxt);
}
text_update_line_edited(text->curl);
@@ -2840,16 +2890,18 @@ static int text_insert_exec(bContext *C, wmOperator *op)
str = RNA_string_get_alloc(op->ptr, "text", NULL, 0);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+
if (st && st->overwrite) {
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, &i);
- done |= txt_replace_char(text, code);
+ done |= txt_replace_char(text, utxt, code);
}
}
else {
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, &i);
- done |= txt_add_char(text, code);
+ done |= txt_add_char(text, utxt, code);
}
}
@@ -2919,6 +2971,9 @@ void TEXT_OT_insert(wmOperatorType *ot)
ot->invoke = text_insert_invoke;
ot->poll = text_edit_poll;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
/* properties */
prop = RNA_def_string(ot->srna, "text", NULL, 0, "Text", "Text to insert at the cursor position");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -2955,7 +3010,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
if (found) {
if (mode == TEXT_REPLACE) {
- txt_insert_buf(text, st->replacestr);
+ TextUndoBuf *utxt = ED_text_undo_push_init(C);
+ txt_insert_buf(text, utxt, st->replacestr);
if (text->curl && text->curl->format) {
MEM_freeN(text->curl->format);
text->curl->format = NULL;
@@ -3024,6 +3080,9 @@ void TEXT_OT_replace(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_replace_exec;
ot->poll = text_space_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/******************* find set selected *********************/
@@ -3081,6 +3140,9 @@ void TEXT_OT_replace_set_selected(wmOperatorType *ot)
/* api callbacks */
ot->exec = text_replace_set_selected_exec;
ot->poll = text_space_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
}
/****************** resolve conflict operator ******************/
@@ -3201,26 +3263,3 @@ void TEXT_OT_to_3d_object(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text");
}
-
-
-/************************ undo ******************************/
-
-void ED_text_undo_step(bContext *C, int step)
-{
- Text *text = CTX_data_edit_text(C);
-
- if (!text)
- return;
-
- if (step == 1)
- txt_do_undo(text);
- else if (step == -1)
- txt_do_redo(text);
-
- text_update_edited(text);
-
- text_update_cursor_moved(C);
- text_drawcache_tag_update(CTX_wm_space_text(C), 1);
- WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
-}
-
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
new file mode 100644
index 00000000000..729522cc8f4
--- /dev/null
+++ b/source/blender/editors/space_text/text_undo.c
@@ -0,0 +1,185 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_undo.c
+ * \ingroup sptext
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_text_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_array_utils.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_text.h"
+#include "BKE_undo_system.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_text.h"
+#include "ED_curve.h"
+#include "ED_screen.h"
+#include "ED_undo.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "text_intern.h"
+#include "text_format.h"
+
+/* TODO(campbell): undo_system: move text undo out of text block. */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct TextUndoStep {
+ UndoStep step;
+ UndoRefID_Text text_ref;
+ TextUndoBuf data;
+} TextUndoStep;
+
+static bool text_undosys_poll(bContext *C)
+{
+ Text *text = CTX_data_edit_text(C);
+ if (text == NULL) {
+ return false;
+ }
+ if (ID_IS_LINKED(text)) {
+ return false;
+ }
+ return true;
+}
+
+static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ BLI_assert(BLI_array_is_zeroed(&us->data, 1));
+
+ UNUSED_VARS(C);
+ /* XXX, use to set the undo type only. */
+
+ us->data.buf = NULL;
+ us->data.len = 0;
+ us->data.pos = -1;
+}
+
+static bool text_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+
+ Text *text = CTX_data_edit_text(C);
+
+ /* No undo data was generated. Hint, use global undo here. */
+ if ((us->data.pos == -1) || (us->data.buf == NULL)) {
+ return false;
+ }
+
+ us->text_ref.ptr = text;
+
+ us->step.data_size = us->data.len;
+
+ return true;
+}
+
+static void text_undosys_step_decode(struct bContext *C, UndoStep *us_p, int dir)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ Text *text = us->text_ref.ptr;
+
+ if (dir < 0) {
+ TextUndoBuf data = us->data;
+ txt_do_undo(text, &data);
+ }
+ else {
+ TextUndoBuf data = us->data;
+ data.pos = -1;
+ txt_do_redo(text, &data);
+ }
+
+ text_update_edited(text);
+ text_update_cursor_moved(C);
+ text_drawcache_tag_update(CTX_wm_space_text(C), 1);
+ WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+}
+
+static void text_undosys_step_free(UndoStep *us_p)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ MEM_SAFE_FREE(us->data.buf);
+}
+
+static void text_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
+}
+
+/* Export for ED_undo_sys. */
+
+void ED_text_undosys_type(UndoType *ut)
+{
+ ut->name = "Text";
+ ut->poll = text_undosys_poll;
+ ut->step_encode_init = text_undosys_step_encode_init;
+ ut->step_encode = text_undosys_step_encode;
+ ut->step_decode = text_undosys_step_decode;
+ ut->step_free = text_undosys_step_free;
+
+ ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref;
+
+ ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+ ut->use_context = false;
+
+ ut->step_size = sizeof(TextUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/* Use operator system to finish the undo step. */
+TextUndoBuf *ED_text_undo_push_init(bContext *C)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT);
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ return &us->data;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 11dc4d10f2a..d80ef486663 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -54,7 +54,7 @@
#include "WM_types.h"
#include "ED_mesh.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_screen.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 5e3c783c1b6..dfa64bd2015 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -55,7 +55,7 @@
#include "RNA_access.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 7708d1abe2e..d9d1f01de60 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1715,23 +1715,13 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
TransInfo *t = (TransInfo *)customdata;
if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) {
- float vecrot[3], cent[2];
+ float cent[2];
int mval[2];
mval[0] = x;
mval[1] = y;
- copy_v3_v3(vecrot, t->center);
- if (t->flag & T_EDIT) {
- Object *ob = t->obedit;
- if (ob) mul_m4_v3(ob->obmat, vecrot);
- }
- else if (t->flag & T_POSE) {
- Object *ob = t->poseobj;
- if (ob) mul_m4_v3(ob->obmat, vecrot);
- }
-
- projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
glPushMatrix();
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 5621eede543..08bd36fe95c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -979,7 +979,7 @@ static void setNearestAxis3d(TransInfo *t)
* of two 2D points 30 pixels apart (that's the last factor in the formula) after
* projecting them with ED_view3d_win_to_delta and then get the length of that vector.
*/
- zfac = mul_project_m4_v3_zfac(t->persmat, t->center);
+ zfac = mul_project_m4_v3_zfac(t->persmat, t->center_global);
zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f;
for (i = 0; i < 3; i++) {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 4e098cd7585..5a6bcdd0d4f 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1887,14 +1887,6 @@ void calculateCenter(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
/* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */
- float vec[3];
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(vec, ob->obmat, t->center);
- }
- else {
- copy_v3_v3(vec, t->center);
- }
/* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
* and never used in other cases.
@@ -1903,7 +1895,7 @@ void calculateCenter(TransInfo *t)
* for a region different from RGN_TYPE_WINDOW.
*/
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
- t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, vec, NULL);
+ t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL);
}
else {
t->zfac = 0.0f;
diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt
new file mode 100644
index 00000000000..89832604ed8
--- /dev/null
+++ b/source/blender/editors/undo/CMakeLists.txt
@@ -0,0 +1,45 @@
+# ***** 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.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/clog
+)
+
+set(SRC
+ ed_undo.c
+ memfile_undo.c
+ undo_system_types.c
+
+ undo_intern.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_editor_undo "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/undo/ed_undo.c
index d791818331e..d8b194e3336 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -25,17 +25,16 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/util/undo.c
- * \ingroup edutil
+/** \file blender/editors/undo/ed_undo.c
+ * \ingroup edundo
*/
-#include <stdlib.h>
#include <string.h>
-#include <math.h>
#include "MEM_guardedalloc.h"
-#include "DNA_object_types.h"
+#include "CLG_log.h"
+
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
@@ -47,20 +46,12 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
-#include "ED_armature.h"
-#include "ED_particle.h"
-#include "ED_curve.h"
#include "ED_gpencil.h"
-#include "ED_lattice.h"
-#include "ED_mball.h"
-#include "ED_mesh.h"
-#include "ED_object.h"
#include "ED_render.h"
#include "ED_screen.h"
-#include "ED_paint.h"
-#include "ED_util.h"
-#include "ED_text.h"
+#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -71,44 +62,37 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "util_intern.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo"};
-/* ***************** generic undo system ********************* */
+/* -------------------------------------------------------------------- */
+/** \name Generic Undo System Access
+ *
+ * Non-operator undo editor functions.
+ * \{ */
void ED_undo_push(bContext *C, const char *str)
{
- Object *obedit = CTX_data_edit_object(C);
- Object *obact = CTX_data_active_object(C);
-
- if (G.debug & G_DEBUG)
- printf("%s: %s\n", __func__, str);
-
- if (obedit) {
- if (U.undosteps == 0) return;
-
- if (obedit->type == OB_MESH)
- undo_push_mesh(C, str);
- else if (ELEM(obedit->type, OB_CURVE, OB_SURF))
- undo_push_curve(C, str);
- else if (obedit->type == OB_FONT)
- undo_push_font(C, str);
- else if (obedit->type == OB_MBALL)
- undo_push_mball(C, str);
- else if (obedit->type == OB_LATTICE)
- undo_push_lattice(C, str);
- else if (obedit->type == OB_ARMATURE)
- undo_push_armature(C, str);
- }
- else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- if (U.undosteps == 0) return;
+ CLOG_INFO(&LOG, 1, "name='%s'", str);
+
+ const int steps = U.undosteps;
- PE_undo_push(CTX_data_scene(C), str);
+ if (steps <= 0) {
+ return;
}
- else if (obact && obact->mode & OB_MODE_SCULPT) {
- /* do nothing for now */
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* Only apply limit if this is the last undo step. */
+ if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
+ BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
}
- else {
- BKE_undo_write(C, str);
+
+ BKE_undosys_step_push(wm->undo_stack, C, str);
+
+ if (U.undomemory != 0) {
+ const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
+ BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit);
}
WM_file_tag_modified();
@@ -117,13 +101,11 @@ void ED_undo_push(bContext *C, const char *str)
/* note: also check undo_history_exec() in bottom if you change notifiers */
static int ed_undo_step(bContext *C, int step, const char *undoname)
{
+ CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- Main *bmain = CTX_data_main(C);
+ // Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
/* undo during jobs are running can easily lead to freeing data using by jobs,
* or they can just lead to freezing job in some other cases */
@@ -131,100 +113,45 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
return OPERATOR_CANCELLED;
}
+ /* TODO(campbell): undo_system: use undo system */
/* grease pencil can be can be used in plenty of spaces, so check it first */
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
}
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
-
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) {
- if (U.uiflag & USER_GLOBALUNDO) {
- ED_viewport_render_kill_jobs(wm, bmain, true);
- BKE_undo_name(C, undoname);
- }
- }
-
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
- }
- }
-
- if (sa && (sa->spacetype == SPACE_TEXT)) {
- ED_text_undo_step(C, step);
- }
- else if (obedit) {
- if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- if (undoname)
- undo_editmode_name(C, undoname);
- else
- undo_editmode_step(C, step);
-
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
- }
- }
- else {
- /* Note: we used to do a fall-through here where if the
- * mode-specific undo system had no more steps to undo (or
- * redo), the global undo would run.
- *
- * That was inconsistent with editmode, and also makes for
- * unecessarily tricky interaction with the other undo
- * systems. */
- if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
- ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname);
+ /* Undo System */
+ {
+ if (undoname) {
+ UndoStep *step_data = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
+ BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data);
}
- else if (obact && obact->mode & OB_MODE_SCULPT) {
- ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname);
- }
- else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- if (step == 1)
- PE_undo(scene);
- else
- PE_redo(scene);
- }
- else if (U.uiflag & USER_GLOBALUNDO) {
- // note python defines not valid here anymore.
- //#ifdef WITH_PYTHON
- // XXX BPY_scripts_clear_pyobjects();
- //#endif
-
- /* for global undo/redo we should just clear the editmode stack */
- /* for example, texface stores image pointers */
- undo_editmode_clear();
-
- ED_viewport_render_kill_jobs(wm, bmain, true);
-
- if (undoname)
- BKE_undo_name(C, undoname);
- else
- BKE_undo_step(C, step);
-
- scene = CTX_data_scene(C);
-
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ else {
+ BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
}
}
-
+
WM_event_add_notifier(C, NC_WINDOW, NULL);
WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
if (win) {
win->addmousemove = true;
}
-
+
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();
+ {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack->steps.last) {
+ const UndoStep *us = wm->undo_stack->steps.last;
+ if (STREQ(str, us->name)) {
+ return;
+ }
+ }
- if (last_undo && STREQ(str, last_undo)) {
- return;
}
/* push as usual */
@@ -265,49 +192,29 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
/* name optionally, function used to check for operator redo panel */
bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
- Object *obedit = CTX_data_edit_object(C);
- Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
-
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- return 1;
- }
- }
-
- if (sa && (sa->spacetype == SPACE_TEXT)) {
- return 1;
- }
- else if (obedit) {
- if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- return undo_editmode_is_valid(undoname);
- }
- }
- else {
-
- /* if below tests fail, global undo gets executed */
-
- if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
- if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname))
- return 1;
- }
- else if (obact && obact->mode & OB_MODE_SCULPT) {
- if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname))
- return 1;
- }
- else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_is_valid(CTX_data_scene(C));
- }
-
- if (U.uiflag & USER_GLOBALUNDO) {
- return BKE_undo_is_valid(undoname);
- }
- }
- return 0;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
+}
+
+/**
+ * Ideally we wont access the stack directly,
+ * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
+ *
+ * Using global isn't great, this just avoids doing inline,
+ * causing 'BKE_global.h' & 'BKE_main.h' includes.
+ */
+UndoStack *ED_undo_stack_get(void)
+{
+ wmWindowManager *wm = G.main->wm.first;
+ return wm->undo_stack;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo, Undo Push & Redo Operators
+ * \{ */
+
static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
@@ -338,19 +245,17 @@ static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
static int ed_undo_redo_poll(bContext *C)
{
wmOperator *last_op = WM_operator_last_redo(C);
- return last_op && ED_operator_screenactive(C) &&
+ return last_op && ED_operator_screenactive(C) &&
WM_operator_check_ui_enabled(C, last_op->type->name);
}
-/* ********************** */
-
void ED_OT_undo(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Undo";
ot->description = "Undo previous action";
ot->idname = "ED_OT_undo";
-
+
/* api callbacks */
ot->exec = ed_undo_exec;
ot->poll = ED_operator_screenactive;
@@ -362,7 +267,7 @@ void ED_OT_undo_push(wmOperatorType *ot)
ot->name = "Undo Push";
ot->description = "Add an undo state (internal use only)";
ot->idname = "ED_OT_undo_push";
-
+
/* api callbacks */
ot->exec = ed_undo_push_exec;
@@ -377,7 +282,7 @@ void ED_OT_redo(wmOperatorType *ot)
ot->name = "Redo";
ot->description = "Redo previous action";
ot->idname = "ED_OT_redo";
-
+
/* api callbacks */
ot->exec = ed_redo_exec;
ot->poll = ED_operator_screenactive;
@@ -389,18 +294,25 @@ void ED_OT_undo_redo(wmOperatorType *ot)
ot->name = "Undo and Redo";
ot->description = "Undo and redo previous action";
ot->idname = "ED_OT_undo_redo";
-
+
/* api callbacks */
ot->exec = ed_undo_redo_exec;
ot->poll = ed_undo_redo_poll;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Repeat
+ * \{ */
+
/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
{
int ret = 0;
if (op) {
+ CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
wmWindowManager *wm = CTX_wm_manager(C);
struct Scene *scene = CTX_data_scene(C);
@@ -461,9 +373,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
CTX_wm_region_set(C, ar);
}
else {
- if (G.debug & G_DEBUG) {
- printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n");
- }
+ CLOG_WARN(&LOG, "called with NULL 'op'");
}
return ret;
@@ -480,114 +390,50 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev
ED_undo_operator_repeat(C, (wmOperator *)arg_op);
}
+/** \} */
-/* ************************** */
-
-enum {
- UNDOSYSTEM_GLOBAL = 1,
- UNDOSYSTEM_EDITMODE = 2,
- UNDOSYSTEM_PARTICLE = 3,
- UNDOSYSTEM_IMAPAINT = 4,
- UNDOSYSTEM_SCULPT = 5,
-};
-
-static int get_undo_system(bContext *C)
-{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
- ScrArea *sa = CTX_wm_area(C);
-
- /* first check for editor undo */
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
-
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE))
- return UNDOSYSTEM_IMAPAINT;
- }
- }
- /* find out which undo system */
- if (obedit) {
- if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- return UNDOSYSTEM_EDITMODE;
- }
- }
- else {
- if (obact) {
- if (obact->mode & OB_MODE_PARTICLE_EDIT)
- return UNDOSYSTEM_PARTICLE;
- else if (obact->mode & OB_MODE_TEXTURE_PAINT) {
- if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE))
- return UNDOSYSTEM_IMAPAINT;
- }
- else if (obact->mode & OB_MODE_SCULPT) {
- if (!ED_undo_paint_empty(UNDO_PAINT_MESH))
- return UNDOSYSTEM_SCULPT;
- }
- }
- if (U.uiflag & USER_GLOBALUNDO)
- return UNDOSYSTEM_GLOBAL;
- }
-
- return 0;
-}
+/* -------------------------------------------------------------------- */
+/** \name Undo History Operator
+ * \{ */
/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
+static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
int i = 0;
- bool active;
-
- while (true) {
- const char *name = NULL;
-
- if (undosys == UNDOSYSTEM_PARTICLE) {
- name = PE_undo_get_name(CTX_data_scene(C), i, &active);
- }
- else if (undosys == UNDOSYSTEM_EDITMODE) {
- name = undo_editmode_get_name(C, i, &active);
- }
- else if (undosys == UNDOSYSTEM_IMAPAINT) {
- name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active);
- }
- else if (undosys == UNDOSYSTEM_SCULPT) {
- name = ED_undo_paint_get_name(C, UNDO_PAINT_MESH, i, &active);
- }
- else {
- name = BKE_undo_get_name(i, &active);
- }
-
- if (name) {
- item_tmp.identifier = name;
- /* XXX This won't work with non-default contexts (e.g. operators) :/ */
- item_tmp.name = IFACE_(name);
- if (active)
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return NULL;
+ }
+
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
+ if (us->skip == false) {
+ item_tmp.identifier = us->name;
+ item_tmp.name = IFACE_(us->name);
+ if (us == wm->undo_stack->step_active) {
item_tmp.icon = ICON_RESTRICT_VIEW_OFF;
- else
+ }
+ else {
item_tmp.icon = ICON_NONE;
- item_tmp.value = i++;
+ }
+ item_tmp.value = i;
RNA_enum_item_add(&item, totitem, &item_tmp);
}
- else
- break;
}
-
RNA_enum_item_end(&item, totitem);
-
+
return item;
}
static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- int undosys, totitem = 0;
-
- undosys = get_undo_system(C);
-
- if (undosys) {
- const EnumPropertyItem *item = rna_undo_itemf(C, undosys, &totitem);
-
+ int totitem = 0;
+
+ {
+ const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
+
if (totitem > 0) {
uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
@@ -596,7 +442,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
const int col_size = 20 + totitem / 12;
int i, c;
bool add_col = true;
-
+
for (c = 0, i = totitem; i--;) {
if (add_col && !(c % col_size)) {
column = uiLayoutColumn(split, false);
@@ -608,12 +454,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
add_col = true;
}
}
-
+
MEM_freeN((void *)item);
-
+
UI_popup_menu_end(C, pup);
}
-
+
}
return OPERATOR_CANCELLED;
}
@@ -621,30 +467,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
/* note: also check ed_undo_step() in top if you change notifiers */
static int undo_history_exec(bContext *C, wmOperator *op)
{
- if (RNA_struct_property_is_set(op->ptr, "item")) {
- int undosys = get_undo_system(C);
- int item = RNA_int_get(op->ptr, "item");
-
- if (undosys == UNDOSYSTEM_PARTICLE) {
- PE_undo_number(CTX_data_scene(C), item);
- }
- else if (undosys == UNDOSYSTEM_EDITMODE) {
- undo_editmode_number(C, item + 1);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
- }
- else if (undosys == UNDOSYSTEM_IMAPAINT) {
- ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item);
- }
- else if (undosys == UNDOSYSTEM_SCULPT) {
- ED_undo_paint_step_num(C, UNDO_PAINT_MESH, item);
- }
- else {
- ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
- BKE_undo_number(C, item);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
- }
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ int item = RNA_property_int_get(op->ptr, prop);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ BKE_undosys_step_undo_from_index(wm->undo_stack, C, item);
WM_event_add_notifier(C, NC_WINDOW, NULL);
-
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -656,14 +484,14 @@ void ED_OT_undo_history(wmOperatorType *ot)
ot->name = "Undo History";
ot->description = "Redo specific action in history";
ot->idname = "ED_OT_undo_history";
-
+
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
ot->poll = ED_operator_screenactive;
-
+
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
-
+/** \} */
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
new file mode 100644
index 00000000000..a0f7ebac477
--- /dev/null
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -0,0 +1,149 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/undo/memfile_undo.c
+ * \ingroup edundo
+ *
+ * Wrapper between 'ED_undo.h' and 'BKE_undo_system.h' API's.
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_sys_types.h"
+
+#include "DNA_object_enums.h"
+
+#include "BKE_blender_undo.h"
+#include "BKE_context.h"
+#include "BKE_undo_system.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_undo.h"
+#include "ED_render.h"
+
+
+#include "../blenloader/BLO_undofile.h"
+
+#include "undo_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct MemFileUndoStep {
+ UndoStep step;
+ MemFileUndoData *data;
+} MemFileUndoStep;
+
+static bool memfile_undosys_poll(bContext *UNUSED(C))
+{
+ /* other poll functions must run first, this is a catch-all. */
+
+ if ((U.uiflag & USER_GLOBALUNDO) == 0) {
+ return false;
+ }
+ return true;
+}
+
+static bool memfile_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ MemFileUndoStep *us = (MemFileUndoStep *)us_p;
+
+ /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */
+ struct Main *bmain = CTX_data_main(C);
+
+ /* can be NULL, use when set. */
+ MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_same_type_prev(us_p);
+ us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL);
+ us->step.data_size = us->data->undo_size;
+ return true;
+}
+
+static void memfile_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* Loading the content will correctly switch into compatible non-object modes. */
+ ED_object_mode_set(C, OB_MODE_OBJECT);
+
+ /* This is needed so undoing/redoing doesn't crash with threaded previews going */
+ ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
+ MemFileUndoStep *us = (MemFileUndoStep *)us_p;
+ BKE_memfile_undo_decode(us->data, C);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
+}
+
+static void memfile_undosys_step_free(UndoStep *us_p)
+{
+ /* To avoid unnecessary slow down, free backwards (so we don't need to merge when clearing all). */
+ MemFileUndoStep *us = (MemFileUndoStep *)us_p;
+ if (us_p->next != NULL) {
+ UndoStep *us_next_p = BKE_undosys_step_same_type_next(us_p);
+ if (us_next_p != NULL) {
+ MemFileUndoStep *us_next = (MemFileUndoStep *)us_next_p;
+ BLO_memfile_merge(&us->data->memfile, &us_next->data->memfile);
+ }
+ }
+
+ BKE_memfile_undo_free(us->data);
+}
+
+/* Export for ED_undo_sys. */
+void ED_memfile_undosys_type(UndoType *ut)
+{
+ ut->name = "Global Undo";
+ ut->poll = memfile_undosys_poll;
+ ut->step_encode = memfile_undosys_step_encode;
+ ut->step_decode = memfile_undosys_step_decode;
+ ut->step_free = memfile_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(MemFileUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Ideally we wouldn't need to export global undo internals, there are some cases where it's needed though.
+ */
+static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p)
+{
+ MemFileUndoStep *us = (MemFileUndoStep *)us_p;
+ return &us->data->memfile;
+}
+
+struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack)
+{
+ UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE);
+ if (us) {
+ return ed_undosys_step_get_memfile(us);
+ }
+ return NULL;
+}
+
+
+/** \} */
diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/undo/undo_intern.h
index 0f650330951..671f9637d65 100644
--- a/source/blender/editors/util/util_intern.h
+++ b/source/blender/editors/undo/undo_intern.h
@@ -15,32 +15,21 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/util/util_intern.h
- * \ingroup edutil
+/** \file blender/editors/undo/undo_intern.h
+ * \ingroup edundo
*/
-
-#ifndef __UTIL_INTERN_H__
-#define __UTIL_INTERN_H__
+#ifndef __UNDO_INTERN_H__
+#define __UNDO_INTERN_H__
/* internal exports only */
-/* editmode_undo.c */
-void undo_editmode_name(struct bContext *C, const char *undoname);
-bool undo_editmode_is_valid(const char *undoname);
-const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active);
-void *undo_editmode_get_prev(struct Object *ob);
-void undo_editmode_step(struct bContext *C, int step);
-void undo_editmode_number(struct bContext *C, int nr);
+struct UndoType;
-#endif /* __UTIL_INTERN_H__ */
+/* memfile_undo.c */
+void ED_memfile_undosys_type(struct UndoType *ut);
+#endif /* __UNDO_INTERN_H__ */
diff --git a/source/blender/editors/undo/undo_system_types.c b/source/blender/editors/undo/undo_system_types.c
new file mode 100644
index 00000000000..75c3d2cc1b7
--- /dev/null
+++ b/source/blender/editors/undo/undo_system_types.c
@@ -0,0 +1,74 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/undo/undo_system_types.c
+ * \ingroup edundo
+ */
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+
+#include "ED_armature.h"
+#include "ED_curve.h"
+#include "ED_lattice.h"
+#include "ED_mball.h"
+#include "ED_mesh.h"
+#include "ED_paint.h"
+#include "ED_particle.h"
+#include "ED_sculpt.h"
+#include "ED_text.h"
+#include "ED_undo.h"
+#include "undo_intern.h"
+
+/* Keep last */
+#include "BKE_undo_system.h"
+
+void ED_undosys_type_init(void)
+{
+ /* Edit Modes */
+ BKE_undosys_type_append(ED_armature_undosys_type);
+ BKE_undosys_type_append(ED_curve_undosys_type);
+ BKE_undosys_type_append(ED_font_undosys_type);
+ BKE_undosys_type_append(ED_lattice_undosys_type);
+ BKE_undosys_type_append(ED_mball_undosys_type);
+ BKE_undosys_type_append(ED_mesh_undosys_type);
+
+ /* Paint Modes */
+ BKE_UNDOSYS_TYPE_IMAGE = BKE_undosys_type_append(ED_image_undosys_type);
+
+ BKE_UNDOSYS_TYPE_SCULPT = BKE_undosys_type_append(ED_sculpt_undosys_type);
+
+ BKE_UNDOSYS_TYPE_PARTICLE = BKE_undosys_type_append(ED_particle_undosys_type);
+
+ BKE_UNDOSYS_TYPE_PAINTCURVE = BKE_undosys_type_append(ED_paintcurve_undosys_type);
+
+ /* Text editor */
+ BKE_UNDOSYS_TYPE_TEXT = BKE_undosys_type_append(ED_text_undosys_type);
+
+ /* Keep global undo last (as a fallback). */
+ BKE_UNDOSYS_TYPE_MEMFILE = BKE_undosys_type_append(ED_memfile_undosys_type);
+}
+
+void ED_undosys_type_free(void)
+{
+ BKE_undosys_type_free_all();
+}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index a8225bb64d1..8657c876d47 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -41,11 +41,8 @@ set(INC_SYS
set(SRC
ed_transverts.c
ed_util.c
- editmode_undo.c
numinput.c
- undo.c
- util_intern.h
# general includes
../include/BIF_gl.h
../include/BIF_glutil.h
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 57ff8b6db01..03d0b4a8d48 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -58,6 +58,7 @@
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -89,6 +90,10 @@ void ED_editors_init(bContext *C)
Object *ob, *obact = (sce && sce->basact) ? sce->basact->object : NULL;
ID *data;
+ if (wm->undo_stack == NULL) {
+ wm->undo_stack = BKE_undosys_stack_create();
+ }
+
/* This is called during initialization, so we don't want to store any reports */
ReportList *reports = CTX_wm_reports(C);
int reports_flag_prev = reports->flag & ~RPT_STORE;
@@ -128,9 +133,15 @@ void ED_editors_exit(bContext *C)
return;
/* frees all editmode undos */
- undo_editmode_clear();
- ED_undo_paint_free();
-
+ if (G.main->wm.first) {
+ wmWindowManager *wm = G.main->wm.first;
+ /* normally we don't check for NULL undo stack, do here since it may run in different context. */
+ if (wm->undo_stack) {
+ BKE_undosys_stack_destroy(wm->undo_stack);
+ wm->undo_stack = NULL;
+ }
+ }
+
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->obedit) {
Object *ob = sce->obedit;
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
deleted file mode 100644
index fa697a0f006..00000000000
--- a/source/blender/editors/util/editmode_undo.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * ***** 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) 2004 Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/util/editmode_undo.c
- * \ingroup edutil
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_blender_undo.h"
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-
-#include "ED_util.h"
-#include "ED_mesh.h"
-
-#include "util_intern.h"
-
-/* ****** XXX ***** */
-static void error(const char *UNUSED(arg)) {}
-/* ****** XXX ***** */
-
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- /** copy of edit-mode object ID */
- ID id;
- /** pointer to edited object */
- Object *ob;
- /** type of edited object */
- int type;
- void *undodata;
- uintptr_t undosize;
- char name[BKE_UNDO_STR_MAX];
-
- /** Use context to retrieve current edit-data. */
- void * (*getdata)(bContext * C);
- /** Pointer to function freeing data. */
- void (*freedata)(void *);
- /** Data to edit-mode conversion. */
- void (*to_editmode)(void *, void *, void *);
- /** Edit-mode to data conversion. */
- void * (*from_editmode)(void *, void *);
- /** Check if undo data is still valid. */
- int (*validate_undo)(void *, void *);
-} UndoElem;
-
-static ListBase g_undobase = {NULL, NULL};
-static UndoElem *g_curundo = NULL;
-
-static void undo_restore(UndoElem *undo, void *editdata, void *obdata)
-{
- if (undo) {
- undo->to_editmode(undo->undodata, editdata, obdata);
- }
-}
-
-/**
- * name can be a dynamic string
- * See #UndoElem for callbacks docs.
- * */
-void undo_editmode_push(
- bContext *C, const char *name,
- void * (*getdata)(bContext * C),
- void (*freedata)(void *),
- void (*to_editmode)(void *, void *, void *),
- void *(*from_editmode)(void *, void *),
- int (*validate_undo)(void *, void *))
-{
- UndoElem *uel;
- Object *obedit = CTX_data_edit_object(C);
- void *editdata;
- int nr;
- uintptr_t mem_used, mem_total, mem_max;
-
- /* at first here was code to prevent an "original" key to be inserted twice
- * this was giving conflicts for example when mesh changed due to keys or apply */
-
- /* remove all undos after (also when g_curundo == NULL) */
- while (g_undobase.last != g_curundo) {
- uel = g_undobase.last;
- uel->freedata(uel->undodata);
- BLI_freelinkN(&g_undobase, uel);
- }
-
- /* make new */
- g_curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode");
- BLI_strncpy(uel->name, name, sizeof(uel->name));
- BLI_addtail(&g_undobase, uel);
-
- uel->getdata = getdata;
- uel->freedata = freedata;
- uel->to_editmode = to_editmode;
- uel->from_editmode = from_editmode;
- uel->validate_undo = validate_undo;
-
- /* limit amount to the maximum amount*/
- nr = 0;
- uel = g_undobase.last;
- while (uel) {
- nr++;
- if (nr == U.undosteps) {
- break;
- }
- uel = uel->prev;
- }
- if (uel) {
- while (g_undobase.first != uel) {
- UndoElem *first = g_undobase.first;
- first->freedata(first->undodata);
- BLI_freelinkN(&g_undobase, first);
- }
- }
-
- /* copy */
- mem_used = MEM_get_memory_in_use();
- editdata = getdata(C);
- g_curundo->undodata = g_curundo->from_editmode(editdata, obedit->data);
- g_curundo->undosize = MEM_get_memory_in_use() - mem_used;
- g_curundo->ob = obedit;
- g_curundo->id = obedit->id;
- g_curundo->type = obedit->type;
-
- if (U.undomemory != 0) {
- /* limit to maximum memory (afterwards, we can't know in advance) */
- mem_total = 0;
- mem_max = ((uintptr_t)U.undomemory) * 1024 * 1024;
-
- uel = g_undobase.last;
- while (uel && uel->prev) {
- mem_total += uel->undosize;
- if (mem_total > mem_max) {
- break;
- }
- uel = uel->prev;
- }
-
- if (uel) {
- if (uel->prev && uel->prev->prev) {
- uel = uel->prev;
- }
- while (g_undobase.first != uel) {
- UndoElem *first = g_undobase.first;
- first->freedata(first->undodata);
- BLI_freelinkN(&g_undobase, first);
- }
- }
- }
-}
-
-/* helper to remove clean other objects from undo stack */
-static void undo_clean_stack(bContext *C)
-{
- UndoElem *uel;
- Object *obedit = CTX_data_edit_object(C);
-
- /* global undo changes pointers, so we also allow identical names */
- /* side effect: when deleting/renaming object and start editing new one with same name */
-
- uel = g_undobase.first;
- while (uel) {
- void *editdata = uel->getdata(C);
- bool is_valid = false;
- UndoElem *uel_next = uel->next;
-
- /* for when objects are converted, renamed, or global undo changes pointers... */
- if (uel->type == obedit->type) {
- if (STREQ(uel->id.name, obedit->id.name)) {
- if (uel->validate_undo == NULL) {
- is_valid = true;
- }
- else if (uel->validate_undo(uel->undodata, editdata)) {
- is_valid = true;
- }
- }
- }
- if (is_valid) {
- uel->ob = obedit;
- }
- else {
- if (uel == g_curundo) {
- g_curundo = NULL;
- }
-
- uel->freedata(uel->undodata);
- BLI_freelinkN(&g_undobase, uel);
- }
-
- uel = uel_next;
- }
-
- if (g_curundo == NULL) {
- g_curundo = g_undobase.last;
- }
-}
-
-/**
- * 1 = an undo, -1 is a redo.
- * we have to make sure 'g_curundo' remains at current situation
- */
-void undo_editmode_step(bContext *C, int step)
-{
- Object *obedit = CTX_data_edit_object(C);
-
- /* prevent undo to happen on wrong object, stack can be a mix */
- undo_clean_stack(C);
-
- if (step == 0) {
- undo_restore(g_curundo, g_curundo->getdata(C), obedit->data);
- }
- else if (step == 1) {
- if (g_curundo == NULL || g_curundo->prev == NULL) {
- error("No more steps to undo");
- }
- else {
- if (G.debug & G_DEBUG) printf("undo %s\n", g_curundo->name);
- g_curundo = g_curundo->prev;
- undo_restore(g_curundo, g_curundo->getdata(C), obedit->data);
- }
- }
- else {
- /* g_curundo has to remain current situation! */
- if (g_curundo == NULL || g_curundo->next == NULL) {
- error("No more steps to redo");
- }
- else {
- undo_restore(g_curundo->next, g_curundo->getdata(C), obedit->data);
- g_curundo = g_curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", g_curundo->name);
- }
- }
-
- /* special case for editmesh, mode must be copied back to the scene */
- if (obedit->type == OB_MESH) {
- EDBM_selectmode_to_scene(C);
- }
-
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
-
- /* XXX notifiers */
-}
-
-void undo_editmode_clear(void)
-{
- UndoElem *uel;
-
- uel = g_undobase.first;
- while (uel) {
- uel->freedata(uel->undodata);
- uel = uel->next;
- }
- BLI_freelistN(&g_undobase);
- g_curundo = NULL;
-}
-
-/* based on index nr it does a restore */
-void undo_editmode_number(bContext *C, int nr)
-{
- UndoElem *uel;
- int a = 1;
-
- for (uel = g_undobase.first; uel; uel = uel->next, a++) {
- if (a == nr) {
- break;
- }
- }
- g_curundo = uel;
- undo_editmode_step(C, 0);
-}
-
-void undo_editmode_name(bContext *C, const char *undoname)
-{
- UndoElem *uel;
-
- for (uel = g_undobase.last; uel; uel = uel->prev) {
- if (STREQ(undoname, uel->name)) {
- break;
- }
- }
- if (uel && uel->prev) {
- g_curundo = uel->prev;
- undo_editmode_step(C, 0);
- }
-}
-
-/**
- * \a undoname is optional, when NULL it just checks for existing undo steps
- */
-bool undo_editmode_is_valid(const char *undoname)
-{
- if (undoname) {
- UndoElem *uel;
-
- for (uel = g_undobase.last; uel; uel = uel->prev) {
- if (STREQ(undoname, uel->name)) {
- break;
- }
- }
- return uel != NULL;
- }
- return g_undobase.last != g_undobase.first;
-}
-
-
-/**
- * Get name of undo item, return null if no item with this index.
- *
- * if active pointer, set it to 1 if true
- */
-const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
-{
- UndoElem *uel;
-
- /* prevent wrong numbers to be returned */
- undo_clean_stack(C);
-
- if (r_active) {
- *r_active = false;
- }
-
- uel = BLI_findlink(&g_undobase, nr);
- if (uel) {
- if (r_active && (uel == g_curundo)) {
- *r_active = true;
- }
- return uel->name;
- }
- return NULL;
-}
-
-
-void *undo_editmode_get_prev(Object *ob)
-{
- UndoElem *ue = g_undobase.last;
- if (ue && ue->prev && ue->prev->ob == ob) {
- return ue->prev->undodata;
- }
- return NULL;
-}
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index c3950d8eb83..e73f227dec8 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
IMB_colormanagement.h
IMB_imbuf.h
IMB_imbuf_types.h
+ IMB_metadata.h
IMB_moviecache.h
IMB_thumbs.h
intern/IMB_allocimbuf.h
@@ -81,7 +82,6 @@ set(SRC
intern/IMB_filetype.h
intern/IMB_filter.h
intern/IMB_indexer.h
- intern/IMB_metadata.h
intern/imbuf.h
# orphan include
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index a7f793b5b11..e5cd21a3248 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -380,13 +380,13 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
*
* \attention Defined in scaling.c
*/
-struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
+bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
*
* \attention Defined in scaling.c
*/
-struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
+bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
*
@@ -399,7 +399,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
short IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
-struct ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
+bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -566,22 +566,6 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
const float col[4], struct ColorManagedDisplay *display,
int x1, int y1, int x2, int y2);
-/**
- *
- * \attention Defined in metadata.c
- */
-/** read the field from the image info into the field
- * \param img - the ImBuf that contains the image data
- * \param key - the key of the field
- * \param value - the data in the field, first one found with key is returned,
- * memory has to be allocated by user.
- * \param len - length of value buffer allocated by user.
- * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
- */
-bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
-bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field);
-void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb);
-
/* exported for image tools in blender, to quickly allocate 32 bits rect */
void *imb_alloc_pixels(unsigned int x,
unsigned int y,
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h
index bc0b2c70ecb..6a29fa01594 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/IMB_metadata.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/imbuf/intern/IMB_metadata.h
+/** \file blender/imbuf/IMB_metadata.h
* \ingroup imbuf
*/
@@ -33,7 +33,9 @@
#ifndef __IMB_METADATA_H__
#define __IMB_METADATA_H__
+struct anim;
struct ImBuf;
+struct IDProperty;
/** The metadata is a list of key/value pairs (both char *) that can me
* saved in the header of several image formats.
@@ -41,26 +43,36 @@ struct ImBuf;
* 'Software' and 'Description' (png standard) we'll use keys within the
* Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum'
* etc...
+ *
+ * The keys & values are stored in ID properties, in the group "metadata".
*/
+/** Ensure that the metadata property is a valid IDProperty object.
+ * This is a no-op when *metadata != NULL.
+ */
+void IMB_metadata_ensure(struct IDProperty **metadata);
+void IMB_metadata_free(struct IDProperty *metadata);
-/* free blender ImMetaData struct */
-void IMB_metadata_free(struct ImBuf *img);
+/** Read the field from the image info into the field.
+ * \param metadata - the IDProperty that contains the metadata
+ * \param key - the key of the field
+ * \param value - the data in the field, first one found with key is returned,
+ * memory has to be allocated by user.
+ * \param len - length of value buffer allocated by user.
+ * \return - 1 (true) if metadata is present and value for the key found, 0 (false) otherwise
+ */
+bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, const size_t len);
-/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create
- * before calling this function.
- * \param img - the ImBuf that contains the image data
+/** Set user data in the metadata.
+ * If the field already exists its value is overwritten, otherwise the field
+ * will be added with the given value.
+ * \param metadata - the IDProperty that contains the metadata
* \param key - the key of the field
* \param value - the data to be written to the field. zero terminated string
- * \return - 1 (true) if ImageInfo present, 0 (false) otherwise
*/
-bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value);
+void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value);
-/** delete the key/field par in the ImMetaData struct.
- * \param img - the ImBuf that contains the image data
- * \param key - the key of the field
- * \return - 1 (true) if delete the key/field, 0 (false) otherwise
- */
-bool IMB_metadata_del_field(struct ImBuf *img, const char *key);
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb);
+struct IDProperty *IMB_anim_load_metadata(struct anim *anim);
#endif /* __IMB_METADATA_H__ */
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index c4c4f4405a5..6fa31e122cc 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -93,6 +93,7 @@
struct _AviMovie;
struct anim_index;
+struct IDProperty;
struct anim {
int ib_flags;
@@ -158,6 +159,8 @@ struct anim {
char colorspace[64];
char suffix[64]; /* MAX_NAME - multiview */
+
+ struct IDProperty *metadata;
};
#endif
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 7fc4a65d8d7..faa0b5f7b6e 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -219,7 +219,7 @@ void IMB_freeImBuf(ImBuf *ibuf)
IMB_freezbufImBuf(ibuf);
IMB_freezbuffloatImBuf(ibuf);
freeencodedbufferImBuf(ibuf);
- IMB_metadata_free(ibuf);
+ IMB_metadata_free(ibuf->metadata);
colormanage_cache_free(ibuf);
if (ibuf->dds_data.data != NULL) {
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index a770b34ecc6..f842b69418e 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -68,8 +68,6 @@
#include "MEM_guardedalloc.h"
-#include "BKE_global.h"
-
#ifdef WITH_AVI
# include "AVI_avi.h"
#endif
@@ -82,8 +80,11 @@
#include "IMB_anim.h"
#include "IMB_indexer.h"
+#include "IMB_metadata.h"
#ifdef WITH_FFMPEG
+# include "BKE_global.h" /* ENDIAN_ORDER */
+
# include <libavformat/avformat.h>
# include <libavcodec/avcodec.h>
# include <libavutil/rational.h>
@@ -220,6 +221,7 @@ void IMB_free_anim(struct anim *anim)
free_anim_ffmpeg(anim);
#endif
IMB_free_indices(anim);
+ IMB_metadata_free(anim->metadata);
MEM_freeN(anim);
}
@@ -239,6 +241,26 @@ void IMB_close_anim_proxies(struct anim *anim)
IMB_free_indices(anim);
}
+struct IDProperty *IMB_anim_load_metadata(struct anim *anim)
+{
+#ifdef WITH_FFMPEG
+ AVDictionaryEntry *entry = NULL;
+
+ BLI_assert(anim->pFormatCtx != NULL);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n");
+
+ while (true) {
+ entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX);
+ if (entry == NULL) break;
+
+ /* Delay creation of the property group until there is actual metadata to put in there. */
+ IMB_metadata_ensure(&anim->metadata);
+ IMB_metadata_set_field(anim->metadata, entry->key, entry->value);
+ }
+#endif
+ return anim->metadata;
+}
+
struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
{
struct anim *anim;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index e28c8122006..b2197ecb3b5 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -49,6 +49,7 @@
#include "IMB_filetype.h"
#include "IMB_filter.h"
#include "IMB_moviecache.h"
+#include "IMB_metadata.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 35c7b6363a1..ef9217fbc8c 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -382,7 +382,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
* the information when we write
* it back to disk.
*/
- IMB_metadata_add_field(ibuf, "None", str);
+ IMB_metadata_ensure(&ibuf->metadata);
+ IMB_metadata_set_field(ibuf->metadata, "None", str);
ibuf->flags |= IB_metadata;
MEM_freeN(str);
goto next_stamp_marker;
@@ -408,7 +409,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
*value = '\0'; /* need finish the key string */
value++;
- IMB_metadata_add_field(ibuf, key, value);
+ IMB_metadata_ensure(&ibuf->metadata);
+ IMB_metadata_set_field(ibuf->metadata, key, value);
ibuf->flags |= IB_metadata;
MEM_freeN(str);
next_stamp_marker:
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index da39967a4fe..ef103f7afcf 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -45,97 +45,69 @@
#include "IMB_metadata.h"
+#define METADATA_MAX_VALUE_LENGTH 1024
-void IMB_metadata_free(struct ImBuf *img)
+void IMB_metadata_ensure(struct IDProperty **metadata)
{
- if (!img)
+ if (*metadata != NULL) {
return;
- if (!img->metadata) {
+ }
+
+ IDPropertyTemplate val;
+ *metadata = IDP_New(IDP_GROUP, &val, "metadata");
+}
+
+void IMB_metadata_free(struct IDProperty *metadata)
+{
+ if (metadata == NULL) {
return;
}
- IDP_FreeProperty(img->metadata);
- MEM_freeN(img->metadata);
+ IDP_FreeProperty(metadata);
+ MEM_freeN(metadata);
}
-bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len)
+bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *field, const size_t len)
{
IDProperty *prop;
- bool retval = false;
-
- if (!img)
- return false;
- if (!img->metadata)
+ if (metadata == NULL) {
return false;
+ }
- prop = IDP_GetPropertyFromGroup(img->metadata, key);
+ prop = IDP_GetPropertyFromGroup(metadata, key);
if (prop && prop->type == IDP_STRING) {
BLI_strncpy(field, IDP_String(prop), len);
- retval = true;
+ return true;
}
- return retval;
+ return false;
}
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
{
BLI_assert(dimb != simb);
if (simb->metadata) {
- IMB_metadata_free(dimb);
+ IMB_metadata_free(dimb->metadata);
dimb->metadata = IDP_CopyProperty(simb->metadata);
}
}
-bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value)
+void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const char *value)
{
- IDProperty *prop;
-
- if (!img)
- return false;
+ BLI_assert(metadata);
+ IDProperty *prop = IDP_GetPropertyFromGroup(metadata, key);
- if (!img->metadata) {
- IDPropertyTemplate val;
- img->metadata = IDP_New(IDP_GROUP, &val, "metadata");
+ if (prop != NULL && prop->type != IDP_STRING) {
+ IDP_FreeFromGroup(metadata, prop);
+ prop = NULL;
}
- prop = IDP_NewString(value, key, 512);
- return IDP_AddToGroup(img->metadata, prop);
-}
-
-bool IMB_metadata_del_field(struct ImBuf *img, const char *key)
-{
- IDProperty *prop;
-
- if ((!img) || (!img->metadata))
- return false;
-
- prop = IDP_GetPropertyFromGroup(img->metadata, key);
-
- if (prop) {
- IDP_FreeFromGroup(img->metadata, prop);
+ if (prop == NULL) {
+ prop = IDP_NewString(value, key, METADATA_MAX_VALUE_LENGTH);
+ IDP_AddToGroup(metadata, prop);
}
- return false;
-}
-
-bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field)
-{
- IDProperty *prop;
- if (!img)
- return false;
-
- prop = (img->metadata) ? IDP_GetPropertyFromGroup(img->metadata, key) : NULL;
-
- if (!prop) {
- return (IMB_metadata_add_field(img, key, field));
- }
- else if (prop->type == IDP_STRING) {
- IDP_AssignString(prop, field, 1024);
- return true;
- }
- else {
- return false;
- }
+ IDP_AssignString(prop, value, METADATA_MAX_VALUE_LENGTH);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 4e85d70d382..ad04f1fb78d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1790,12 +1790,13 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags,
const Header & header = file->header(0);
Header::ConstIterator iter;
+ IMB_metadata_ensure(&ibuf->metadata);
for (iter = header.begin(); iter != header.end(); iter++) {
const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
/* not all attributes are string attributes so we might get some NULLs here */
if (attrib) {
- IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
+ IMB_metadata_set_field(ibuf->metadata, iter.name(), attrib->value().c_str());
ibuf->flags |= IB_metadata;
}
}
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 857f72e10eb..29fbe79d8db 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -759,8 +759,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
if (flags & IB_metadata) {
png_text *text_chunks;
int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
+ IMB_metadata_ensure(&ibuf->metadata);
for (int i = 0; i < count; i++) {
- IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
+ IMB_metadata_set_field(ibuf->metadata, text_chunks[i].key, text_chunks[i].text);
ibuf->flags |= IB_metadata;
}
}
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 504b59b2b1d..ff92ce15811 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -1550,12 +1550,17 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
}
}
-struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
+/**
+ * Return true if \a ibuf is modified.
+ */
+bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
- if (ibuf == NULL) return (NULL);
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) return (ibuf);
+ if (ibuf == NULL) return false;
+ if (ibuf->rect == NULL && ibuf->rect_float == NULL) return false;
- if (newx == ibuf->x && newy == ibuf->y) { return ibuf; }
+ if (newx == ibuf->x && newy == ibuf->y) {
+ return false;
+ }
/* scaleup / scaledown functions below change ibuf->x and ibuf->y
* so we first scale the Z-buffer (if any) */
@@ -1564,7 +1569,7 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int
/* try to scale common cases in a fast way */
/* disabled, quality loss is unacceptable, see report #18609 (ton) */
if (0 && q_scale_linear_interpolation(ibuf, newx, newy)) {
- return ibuf;
+ return true;
}
if (newx && (newx < ibuf->x)) scaledownx(ibuf, newx);
@@ -1572,14 +1577,17 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int
if (newx && (newx > ibuf->x)) scaleupx(ibuf, newx);
if (newy && (newy > ibuf->y)) scaleupy(ibuf, newy);
- return(ibuf);
+ return true;
}
struct imbufRGBA {
float r, g, b, a;
};
-struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
+/**
+ * Return true if \a ibuf is modified.
+ */
+bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
unsigned int *rect, *_newrect, *newrect;
struct imbufRGBA *rectf, *_newrectf, *newrectf;
@@ -1590,16 +1598,16 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned
rect = NULL; _newrect = NULL; newrect = NULL;
rectf = NULL; _newrectf = NULL; newrectf = NULL;
- if (ibuf == NULL) return(NULL);
+ if (ibuf == NULL) return false;
if (ibuf->rect) do_rect = true;
if (ibuf->rect_float) do_float = true;
- if (do_rect == false && do_float == false) return(ibuf);
+ if (do_rect == false && do_float == false) return false;
- if (newx == ibuf->x && newy == ibuf->y) return(ibuf);
+ if (newx == ibuf->x && newy == ibuf->y) return false;
if (do_rect) {
_newrect = MEM_mallocN(newx * newy * sizeof(int), "scalefastimbuf");
- if (_newrect == NULL) return(ibuf);
+ if (_newrect == NULL) return false;
newrect = _newrect;
}
@@ -1607,7 +1615,7 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned
_newrectf = MEM_mallocN(newx * newy * sizeof(float) * 4, "scalefastimbuf f");
if (_newrectf == NULL) {
if (_newrect) MEM_freeN(_newrect);
- return(ibuf);
+ return false;
}
newrectf = _newrectf;
}
@@ -1643,18 +1651,18 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned
ibuf->mall |= IB_rect;
ibuf->rect = _newrect;
}
-
+
if (do_float) {
imb_freerectfloatImBuf(ibuf);
ibuf->mall |= IB_rectfloat;
ibuf->rect_float = (float *)_newrectf;
}
-
+
scalefast_Z_ImBuf(ibuf, newx, newy);
-
+
ibuf->x = newx;
ibuf->y = newy;
- return(ibuf);
+ return true;
}
/* ******** threaded scaling ******** */
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 3c587684641..2fa5b5a0170 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -430,16 +430,17 @@ static ImBuf *thumb_create_ex(
IMB_scaleImBuf(img, ex, ey);
}
BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri);
- IMB_metadata_change_field(img, "Description", desc);
- IMB_metadata_change_field(img, "Software", "Blender");
- IMB_metadata_change_field(img, "Thumb::URI", uri);
- IMB_metadata_change_field(img, "Thumb::MTime", mtime);
+ IMB_metadata_ensure(&img->metadata);
+ IMB_metadata_set_field(img->metadata, "Software", "Blender");
+ IMB_metadata_set_field(img->metadata, "Thumb::URI", uri);
+ IMB_metadata_set_field(img->metadata, "Description", desc);
+ IMB_metadata_set_field(img->metadata, "Thumb::MTime", mtime);
if (use_hash) {
- IMB_metadata_change_field(img, "X-Blender::Hash", hash);
+ IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash);
}
if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
- IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth);
- IMB_metadata_change_field(img, "Thumb::Image::Height", cheight);
+ IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth);
+ IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight);
}
img->ftype = IMB_FTYPE_PNG;
img->planes = 32;
@@ -589,7 +590,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
- if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) {
+ if (IMB_metadata_get_field(img->metadata, "Thumb::MTime", mtime, sizeof(mtime))) {
regenerate = (st.st_mtime != atol(mtime));
}
else {
@@ -598,7 +599,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
}
if (use_hash && !regenerate) {
- if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) {
+ if (IMB_metadata_get_field(img->metadata, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) {
regenerate = !STREQ(thumb_hash, thumb_hash_curr);
}
else {
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index b5c6deb6b01..d04f5fc87e6 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -36,7 +36,6 @@
#include "BLO_blend_defs.h"
#include "BLO_readfile.h"
-#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_icons.h"
#include "BKE_library.h"
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 76a44aa81f7..9dfe926ddff 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -43,8 +43,6 @@
#include "BLI_fileops.h"
#include "BLI_string.h"
-#include "BKE_global.h"
-
#include "imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -53,6 +51,7 @@
#include "IMB_anim.h"
#ifdef WITH_FFMPEG
+#include "BKE_global.h" /* G.debug */
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 84ec2534e7f..e340d082895 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -46,7 +46,7 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static ImBuf *prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
+static bool prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
{
return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
}
@@ -64,15 +64,11 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->save && type->ftype(type, ibuf)) {
- ImBuf *write_ibuf;
short result = false;
- write_ibuf = prepare_write_imbuf(type, ibuf);
+ prepare_write_imbuf(type, ibuf);
- result = type->save(write_ibuf, name, flags);
-
- if (write_ibuf != ibuf)
- IMB_freeImBuf(write_ibuf);
+ result = type->save(ibuf, name, flags);
return result;
}
@@ -83,9 +79,9 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
return false;
}
-ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
+bool IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
{
- ImBuf *write_ibuf = ibuf;
+ bool changed = false;
if (isfloat) {
/* pass */
@@ -94,8 +90,11 @@ ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
if (ibuf->rect == NULL && ibuf->rect_float) {
ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
IMB_rect_from_float(ibuf);
+ if (ibuf->rect != NULL) {
+ changed = true;
+ }
}
}
- return write_ibuf;
+ return changed;
}
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index a7f3d27e9d2..1691038e13c 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -377,7 +377,12 @@ typedef enum eRotationModes {
typedef struct bPose {
ListBase chanbase; /* list of pose channels, PoseBones in RNA */
struct GHash *chanhash; /* ghash for quicker string lookups */
-
+
+ /* Flat array of pose channels. It references pointers from
+ * chanbase. Used for quick pose channel lookup from an index.
+ */
+ bPoseChannel **chan_array;
+
short flag, pad;
unsigned int proxy_layer; /* proxy layer: copy from armature, gets synced */
int pad1;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f7fd54a77cf..32b0702e208 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -101,17 +101,28 @@ typedef struct AviCodecData {
typedef enum eFFMpegPreset {
FFM_PRESET_NONE,
- FFM_PRESET_ULTRAFAST,
- FFM_PRESET_SUPERFAST,
- FFM_PRESET_VERYFAST,
- FFM_PRESET_FASTER,
- FFM_PRESET_FAST,
- FFM_PRESET_MEDIUM,
- FFM_PRESET_SLOW,
- FFM_PRESET_SLOWER,
- FFM_PRESET_VERYSLOW,
-} eFFMpegPreset;
+#ifdef DNA_DEPRECATED
+ /* Previously used by h.264 to control encoding speed vs. file size. */
+ FFM_PRESET_ULTRAFAST, /* DEPRECATED */
+ FFM_PRESET_SUPERFAST, /* DEPRECATED */
+ FFM_PRESET_VERYFAST, /* DEPRECATED */
+ FFM_PRESET_FASTER, /* DEPRECATED */
+ FFM_PRESET_FAST, /* DEPRECATED */
+ FFM_PRESET_MEDIUM, /* DEPRECATED */
+ FFM_PRESET_SLOW, /* DEPRECATED */
+ FFM_PRESET_SLOWER, /* DEPRECATED */
+ FFM_PRESET_VERYSLOW, /* DEPRECATED */
+#endif
+
+ /* Used by WEBM/VP9 and h.264 to control encoding speed vs. file size.
+ * WEBM/VP9 use these values directly, whereas h.264 map those to
+ * respectively the MEDIUM, SLOWER, and SUPERFAST presets.
+ */
+ FFM_PRESET_GOOD = 10, /* the default and recommended for most applications */
+ FFM_PRESET_BEST, /* recommended if you have lots of time and want the best compression efficiency */
+ FFM_PRESET_REALTIME, /* recommended for live / fast encoding */
+} eFFMpegPreset;
/* Mapping from easily-understandable descriptions to CRF values.
* Assumes we output 8-bit video. Needs to be remapped if 10-bit
@@ -1836,10 +1847,11 @@ enum {
#define R_STAMP_STRIPMETA 0x1000
#define R_STAMP_MEMORY 0x2000
#define R_STAMP_HIDE_LABELS 0x4000
+#define R_STAMP_FRAME_RANGE 0x8000
#define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \
R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \
R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \
- R_STAMP_HIDE_LABELS)
+ R_STAMP_HIDE_LABELS|R_STAMP_FRAME_RANGE)
/* RenderData.alphamode */
#define R_ADDSKY 0
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 17ef098a3bb..163dda678d9 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -59,10 +59,6 @@ typedef struct Text {
TextLine *curl, *sell;
int curc, selc;
- char *undo_buf;
- void *pad;
- int undo_pos, undo_len;
-
double mtime;
} Text;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 687a883f792..20470ba862e 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -58,6 +58,7 @@ struct ReportList;
struct Report;
struct uiLayout;
struct Stereo3dFormat;
+struct UndoStep;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
@@ -154,6 +155,8 @@ typedef struct wmWindowManager {
ListBase timers; /* active timers */
struct wmTimer *autosavetimer; /* timer for auto save */
+ struct UndoStack *undo_stack; /* all undo history (runtime only). */
+
char is_interface_locked; /* indicates whether interface is locked for user interaction */
char par[7];
} wmWindowManager;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index a9e34247cbd..bc2c26c2b2b 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -754,6 +754,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
}
+static IDProperty *rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr, bool UNUSED(create))
+{
+ if (ptr == NULL) {
+ return NULL;
+ }
+ return ptr->data;
+}
+
#else
static void rna_def_ID_properties(BlenderRNA *brna)
@@ -1105,6 +1113,20 @@ static void rna_def_library(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks");
}
+
+/**
+ * \attention This is separate from the above. It allows for RNA functions to
+ * return an IDProperty *. See MovieClip.metadata for a usage example.
+ **/
+static void rna_def_idproperty_wrap_ptr(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "IDPropertyWrapPtr", NULL);
+ RNA_def_struct_idprops_func(srna, "rna_IDPropertyWrapPtr_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
+}
+
void RNA_def_ID(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1122,6 +1144,7 @@ void RNA_def_ID(BlenderRNA *brna)
rna_def_ID_properties(brna);
rna_def_ID_materials(brna);
rna_def_library(brna);
+ rna_def_idproperty_wrap_ptr(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 18e42488829..bec6830f8c3 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1842,14 +1842,14 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
else {
flag = prop->flag;
if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
- *r_info = "This property is for internal use only and can't be edited.";
+ *r_info = N_("This property is for internal use only and can't be edited");
}
}
/* property from linked data-block */
if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
if (!(*r_info)[0]) {
- *r_info = "Can't edit this property from a linked data-block.";
+ *r_info = N_("Can't edit this property from a linked data-block");
}
return false;
}
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index fb743f5236d..d63f3fe76f8 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -33,6 +33,7 @@
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
+#include "RNA_access.h"
#include "RNA_define.h"
#include "rna_internal.h"
@@ -44,6 +45,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "IMB_metadata.h"
#ifdef RNA_RUNTIME
@@ -103,6 +105,22 @@ static void rna_MovieClipUser_proxy_render_settings_update(Main *UNUSED(bmain),
}
}
+static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip)
+{
+ if (clip == NULL || clip->anim == NULL) {
+ return PointerRNA_NULL;
+ }
+
+ IDProperty *metadata = IMB_anim_load_metadata(clip->anim);
+ if (metadata == NULL) {
+ return PointerRNA_NULL;
+ }
+
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr);
+ return ptr;
+}
+
#else
static void rna_def_movieclip_proxy(BlenderRNA *brna)
@@ -257,6 +275,8 @@ static void rna_def_movieclip(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
static const EnumPropertyItem clip_source_items[] = {
{MCLIP_SRC_SEQUENCE, "SEQUENCE", 0, "Image Sequence", "Multiple image files, as a sequence"},
@@ -348,6 +368,14 @@ static void rna_def_movieclip(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
+ /* metadata */
+ func = RNA_def_function(srna, "metadata", "rna_MovieClip_metadata_get");
+ RNA_def_function_ui_description(func, "Retrieve metadata of the movie file");
+ /* return type */
+ parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
rna_def_animdata_common(srna);
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index ccd16e16760..773ca307a8c 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2701,7 +2701,7 @@ static int rna_Node_image_has_views_get(PointerRNA *ptr)
if (!ima || !(ima->rr)) return 0;
- return BLI_listbase_count_ex(&ima->rr->views, 2) > 1;
+ return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1;
}
static const EnumPropertyItem *renderresult_views_add_enum(RenderView *rv)
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 188200eaff9..4c3301d5f9e 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -1293,49 +1293,49 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
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);
+ prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_x");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_x_set", NULL);
RNA_def_property_ui_text(prop, "Damping X", "Damping on the X axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
- prop = RNA_def_property(srna, "spring_damping_y", PROP_FLOAT, PROP_FACTOR);
+ prop = RNA_def_property(srna, "spring_damping_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_y");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_y_set", NULL);
RNA_def_property_ui_text(prop, "Damping Y", "Damping on the Y axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
- prop = RNA_def_property(srna, "spring_damping_z", PROP_FLOAT, PROP_FACTOR);
+ prop = RNA_def_property(srna, "spring_damping_z", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_z");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_z_set", NULL);
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);
+ prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
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);
+ prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
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);
+ prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
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");
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 6cd748c0026..b1b7965286f 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -629,7 +629,7 @@ static const EnumPropertyItem *rna_Property_tags_itemf(
int totitem = 0;
for (const EnumPropertyItem *struct_tags = RNA_struct_property_tag_defines(srna);
- struct_tags->identifier;
+ struct_tags != NULL && struct_tags->identifier != NULL;
struct_tags++)
{
memcpy(&tmp, struct_tags, sizeof(tmp));
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 70fe38cb60d..48c42c44a3d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5451,8 +5451,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
{FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
-// {FFMPEG_H264, "H264", 0, "H.264", ""}, not a container
-// {FFMPEG_XVID, "XVID", 0, "Xvid", ""}, not a container
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
{FFMPEG_FLV, "FLASH", 0, "Flash", ""},
@@ -5460,38 +5458,37 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
};
static const EnumPropertyItem ffmpeg_codec_items[] = {
- {AV_CODEC_ID_NONE, "NONE", 0, "None", ""},
- {AV_CODEC_ID_MPEG1VIDEO, "MPEG1", 0, "MPEG-1", ""},
- {AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""},
- {AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4(divx)", ""},
- {AV_CODEC_ID_HUFFYUV, "HUFFYUV", 0, "HuffYUV", ""},
+ {AV_CODEC_ID_NONE, "NONE", 0, "No Video", "Disables video output, for audio-only renders"},
+ {AV_CODEC_ID_DNXHD, "DNXHD", 0, "DNxHD", ""},
{AV_CODEC_ID_DVVIDEO, "DV", 0, "DV", ""},
- {AV_CODEC_ID_H264, "H264", 0, "H.264", ""},
- {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""},
- {AV_CODEC_ID_FLV1, "FLASH", 0, "Flash Video", ""},
{AV_CODEC_ID_FFV1, "FFV1", 0, "FFmpeg video codec #1", ""},
- {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""},
- {AV_CODEC_ID_DNXHD, "DNXHD", 0, "DNxHD", ""},
+ {AV_CODEC_ID_FLV1, "FLASH", 0, "Flash Video", ""},
+ {AV_CODEC_ID_H264, "H264", 0, "H.264", ""},
+ {AV_CODEC_ID_HUFFYUV, "HUFFYUV", 0, "HuffYUV", ""},
+ {AV_CODEC_ID_MPEG1VIDEO, "MPEG1", 0, "MPEG-1", ""},
+ {AV_CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""},
+ {AV_CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4 (divx)", ""},
{AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""},
+ {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""},
+ {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""},
+ {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""},
{0, NULL, 0, NULL, NULL}
};
+ /* Recommendations come from the FFmpeg wiki, https://trac.ffmpeg.org/wiki/Encode/VP9.
+ * The label for BEST has been changed to "Slowest" so that it fits the "Encoding Speed"
+ * property label in the UI. */
static const EnumPropertyItem ffmpeg_preset_items[] = {
- {FFM_PRESET_ULTRAFAST, "ULTRAFAST", 0, "Ultra fast; biggest file", ""},
- {FFM_PRESET_SUPERFAST, "SUPERFAST", 0, "Super fast", ""},
- {FFM_PRESET_VERYFAST, "VERYFAST", 0, "Very fast", ""},
- {FFM_PRESET_FASTER, "FASTER", 0, "Faster", ""},
- {FFM_PRESET_FAST, "FAST", 0, "Fast", ""},
- {FFM_PRESET_MEDIUM, "MEDIUM", 0, "Medium speed", ""},
- {FFM_PRESET_SLOW, "SLOW", 0, "Slow", ""},
- {FFM_PRESET_SLOWER, "SLOWER", 0, "Slower", ""},
- {FFM_PRESET_VERYSLOW, "VERYSLOW", 0, "Very slow; smallest file", ""},
+ {FFM_PRESET_BEST, "BEST", 0, "Slowest",
+ "Recommended if you have lots of time and want the best compression efficiency"},
+ {FFM_PRESET_GOOD, "GOOD", 0, "Good", "The default and recommended for most applications"},
+ {FFM_PRESET_REALTIME, "REALTIME", 0, "Realtime", "Recommended for fast encoding"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem ffmpeg_crf_items[] = {
- {FFM_CRF_NONE, "NONE", 0, "None; use custom bitrate",
- "Use constant bit rate, rather than constant output quality"},
+ {FFM_CRF_NONE, "NONE", 0, "Constant Bitrate",
+ "Configure constant bit rate, rather than constant output quality"},
{FFM_CRF_LOSSLESS, "LOSSLESS", 0, "Lossless", ""},
{FFM_CRF_PERC_LOSSLESS, "PERC_LOSSLESS", 0, "Perceptually lossless", ""},
{FFM_CRF_HIGH, "HIGH", 0, "High quality", ""},
@@ -5503,14 +5500,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
};
static const EnumPropertyItem ffmpeg_audio_codec_items[] = {
- {AV_CODEC_ID_NONE, "NONE", 0, "None", ""},
- {AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""},
- {AV_CODEC_ID_MP3, "MP3", 0, "MP3", ""},
- {AV_CODEC_ID_AC3, "AC3", 0, "AC3", ""},
+ {AV_CODEC_ID_NONE, "NONE", 0, "No Audio", "Disables audio output, for video-only renders"},
{AV_CODEC_ID_AAC, "AAC", 0, "AAC", ""},
- {AV_CODEC_ID_VORBIS, "VORBIS", 0, "Vorbis", ""},
+ {AV_CODEC_ID_AC3, "AC3", 0, "AC3", ""},
{AV_CODEC_ID_FLAC, "FLAC", 0, "FLAC", ""},
+ {AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""},
+ {AV_CODEC_ID_MP3, "MP3", 0, "MP3", ""},
{AV_CODEC_ID_PCM_S16LE, "PCM", 0, "PCM", ""},
+ {AV_CODEC_ID_VORBIS, "VORBIS", 0, "Vorbis", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -5542,7 +5539,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
- RNA_def_property_ui_text(prop, "Codec", "FFmpeg codec to use");
+ RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE);
@@ -5621,7 +5618,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "ffmpeg_preset");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_preset_items);
- RNA_def_property_enum_default(prop, FFM_PRESET_MEDIUM);
+ RNA_def_property_enum_default(prop, FFM_PRESET_GOOD);
RNA_def_property_ui_text(prop, "Encoding speed",
"Tradeoff between encoding speed and compression ratio");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -6370,7 +6367,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_stamp_date", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_DATE);
- RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image metadata");
+ RNA_def_property_ui_text(prop, "Stamp Date", "Include the current date in image/video metadata");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_frame", PROP_BOOLEAN, PROP_NONE);
@@ -6378,6 +6375,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stamp Frame", "Include the frame number in image metadata");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "use_stamp_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FRAME_RANGE);
+ RNA_def_property_ui_text(prop, "Stamp Frame", "Include the rendered frame range in image/video metadata");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_stamp_camera", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_CAMERA);
RNA_def_property_ui_text(prop, "Stamp Camera", "Include the name of the active camera in image metadata");
@@ -6390,12 +6392,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_stamp_scene", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_SCENE);
- RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image metadata");
+ RNA_def_property_ui_text(prop, "Stamp Scene", "Include the name of the active scene in image/video metadata");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_note", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_NOTE);
- RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image metadata");
+ RNA_def_property_ui_text(prop, "Stamp Note", "Include a custom note in image/video metadata");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_marker", PROP_BOOLEAN, PROP_NONE);
@@ -6405,7 +6407,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_stamp_filename", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_FILENAME);
- RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image metadata");
+ RNA_def_property_ui_text(prop, "Stamp Filename", "Include the .blend filename in image/video metadata");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_sequencer_strip", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index cfd6d0c6db3..33621af69af 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -38,10 +38,11 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_global.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
+#include "IMB_metadata.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -588,6 +589,27 @@ static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
return seq->prop;
}
+static PointerRNA rna_MovieSequence_metadata_get(Sequence *seq)
+{
+ if (seq == NULL || seq->anims.first == NULL) {
+ return PointerRNA_NULL;
+ }
+
+ StripAnim *sanim = seq->anims.first;
+ if (sanim->anim == NULL) {
+ return PointerRNA_NULL;
+ }
+
+ IDProperty *metadata = IMB_anim_load_metadata(sanim->anim);
+ if (metadata == NULL) {
+ return PointerRNA_NULL;
+ }
+
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_IDPropertyWrapPtr, metadata, &ptr);
+ return ptr;
+}
+
static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -1964,7 +1986,9 @@ static void rna_def_movie(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna = RNA_def_struct(brna, "MovieSequence", "Sequence");
RNA_def_struct_ui_text(srna, "Movie Sequence", "Sequence strip to load a video");
RNA_def_struct_sdna(srna, "Sequence");
@@ -1996,6 +2020,14 @@ static void rna_def_movie(BlenderRNA *brna)
"rna_Sequence_filepath_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
+ /* metadata */
+ func = RNA_def_function(srna, "metadata", "rna_MovieSequence_metadata_get");
+ RNA_def_function_ui_description(func, "Retrieve metadata of the movie file");
+ /* return type */
+ parm = RNA_def_pointer(func, "metadata", "IDPropertyWrapPtr", "", "Dict-like object containing the metadata");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
/* multiview */
prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 3bfe1fbcb83..38c297def32 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -905,7 +905,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
RNA_def_property_ui_text(prop, "Clipping",
- "Value under which voxels are considered empty space to optimize caching or rendering");
+ "Value under which voxels are considered empty space to optimize caching or rendering");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index 0287f74587b..d7a862fecbc 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -40,13 +40,13 @@
static void rna_Text_clear(Text *text)
{
- BKE_text_clear(text);
+ BKE_text_clear(text, NULL);
WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
}
static void rna_Text_write(Text *text, const char *str)
{
- BKE_text_write(text, str);
+ BKE_text_write(text, NULL, str);
WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
}
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index d2d82ca23d2..72122fae6b4 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -81,14 +81,6 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
}
-static void freeData(ModifierData *md)
-{
- DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- if (dmd->texture) {
- id_us_min(&dmd->texture->id);
- }
-}
-
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;
@@ -444,7 +436,7 @@ ModifierTypeInfo modifierType_Displace = {
/* applyModifierEM */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ freeData,
+ /* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 65f45c9af64..72c44121e0b 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -48,7 +48,9 @@
#include "BKE_fluidsim.h" /* ensure definitions here match */
#include "BKE_cdderivedmesh.h"
-#include "BKE_global.h" /* G.main->name only */
+#ifdef WITH_MOD_FLUID
+# include "BKE_global.h"
+#endif
#include "MOD_fluidsim_util.h"
#include "MOD_modifiertypes.h"
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 793edf7c370..04de6fae336 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -33,7 +33,6 @@
#include "BKE_cachefile.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
-#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_scene.h"
@@ -45,6 +44,7 @@
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
+# include "BKE_global.h"
#endif
static void initData(ModifierData *md)
@@ -75,10 +75,6 @@ static void freeData(ModifierData *md)
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
- if (mcmd->cache_file) {
- id_us_min(&mcmd->cache_file->id);
- }
-
if (mcmd->reader) {
#ifdef WITH_ALEMBIC
CacheReader_free(mcmd->reader);
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index d1c457526c2..82c6b82d492 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -44,7 +44,6 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
-#include "BKE_global.h"
#include "BKE_lattice.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 0c3781acb19..8fe29c78486 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -78,14 +78,6 @@ static void initData(ModifierData *md)
wmd->defgrp_name[0] = 0;
}
-static void freeData(ModifierData *md)
-{
- WaveModifierData *wmd = (WaveModifierData *) md;
- if (wmd->texture) {
- id_us_min(&wmd->texture->id);
- }
-}
-
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -383,7 +375,7 @@ ModifierTypeInfo modifierType_Wave = {
/* applyModifierEM */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ freeData,
+ /* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index aeb3df42622..8d77747b45d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -79,10 +79,6 @@ static void freeData(ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
curvemapping_free(wmd->cmap_curve);
-
- if (wmd->mask_texture) {
- id_us_min(&wmd->mask_texture->id);
- }
}
static void copyData(ModifierData *md, ModifierData *target)
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 032e154e096..bd1f58e7d5e 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -126,14 +126,6 @@ static void initData(ModifierData *md)
wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
}
-static void freeData(ModifierData *md)
-{
- WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- if (wmd->mask_texture) {
- id_us_min(&wmd->mask_texture->id);
- }
-}
-
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -427,7 +419,7 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* applyModifierEM */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ freeData,
+ /* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index cbc62cdace5..09991887f69 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -286,14 +286,6 @@ static void initData(ModifierData *md)
wmd->max_dist = 1.0f; /* vert arbitrary distance, but don't use 0 */
}
-static void freeData(ModifierData *md)
-{
- WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- if (wmd->mask_texture) {
- id_us_min(&wmd->mask_texture->id);
- }
-}
-
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -616,7 +608,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* applyModifierEM */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ freeData,
+ /* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index 3c165cfcb8a..74e23aed7de 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -202,7 +202,7 @@ void register_node_type_sh_vect_transform(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_CONVERTOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0);
node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_init(&ntype, node_shader_init_vect_transform);
node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
index f9a481e6c7e..e85fec1ec9d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
@@ -41,7 +41,7 @@ static bNodeSocketTemplate sh_node_volume_principled_in[] = {
{ SOCK_FLOAT, 1, N_("Blackbody Intensity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_RGBA, 1, N_("Blackbody Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Temperature"), 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6500.0f},
- { SOCK_STRING, 1, N_("Temperature Attribute"),0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_STRING, 1, N_("Temperature Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index d676b1a1521..0fdc1d86d5c 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -48,7 +48,6 @@
#include "BKE_cloth.h"
#include "BKE_collision.h"
#include "BKE_effect.h"
-#include "BKE_global.h"
#include "BPH_mass_spring.h"
diff --git a/source/blender/python/BPY_extern_clog.h b/source/blender/python/BPY_extern_clog.h
new file mode 100644
index 00000000000..fbe7139ba1b
--- /dev/null
+++ b/source/blender/python/BPY_extern_clog.h
@@ -0,0 +1,35 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BPY_extern_clog.h
+ * \ingroup python
+ *
+ * Logging defines.
+ */
+
+#ifndef __BPY_EXTERN_CLOG_H__
+#define __BPY_EXTERN_CLOG_H__
+
+
+/* bpy_interface.c */
+extern struct CLG_LogRef *BPY_LOG_RNA;
+extern struct CLG_LogRef *BPY_LOG_CONTEXT;
+
+#endif /* __BPY_EXTERN_CLOG_H__ */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 36609c6f29b..6f265b2ae87 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -38,6 +38,8 @@
#include "python_utildefines.h"
+#include "BLI_string.h"
+
#ifndef MATH_STANDALONE
/* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */
#include "BLI_string_utf8.h"
@@ -144,6 +146,15 @@ PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len)
return tuple;
}
+PyObject *PyC_Tuple_PackArray_F64(const double *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i]));
+ }
+ return tuple;
+}
+
PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len)
{
PyObject *tuple = PyTuple_New(len);
@@ -225,22 +236,49 @@ int PyC_ParseBool(PyObject *o, void *p)
/* for debugging */
void PyC_ObSpit(const char *name, PyObject *var)
{
+ const char *null_str = "<null>";
fprintf(stderr, "<%s> : ", name);
if (var == NULL) {
- fprintf(stderr, "<NIL>");
+ fprintf(stderr, "%s\n", null_str);
}
else {
PyObject_Print(var, stderr, 0);
- fprintf(stderr, " ref:%d ", (int)var->ob_refcnt);
- fprintf(stderr, " ptr:%p", (void *)var);
-
- fprintf(stderr, " type:");
- if (Py_TYPE(var))
- fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
- else
- fprintf(stderr, "<NIL>");
+ const PyTypeObject *type = Py_TYPE(var);
+ fprintf(stderr,
+ " ref:%d, ptr:%p, type: %s\n",
+ (int)var->ob_refcnt, (void *)var, type ? type->tp_name : null_str);
+ }
+}
+
+/**
+ * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
+ * Use for logging.
+ */
+void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var)
+{
+ /* No name, creator of string can manage that. */
+ const char *null_str = "<null>";
+ if (var == NULL) {
+ BLI_snprintf(result, result_len, "%s", null_str);
+ }
+ else {
+ const PyTypeObject *type = Py_TYPE(var);
+ PyObject *var_str = PyObject_Repr(var);
+ if (var_str == NULL) {
+ /* We could print error here, but this may be used for generating errors - so don't for now. */
+ PyErr_Clear();
+ }
+ BLI_snprintf(
+ result, result_len,
+ " ref=%d, ptr=%p, type=%s, value=%.200s",
+ (int)var->ob_refcnt,
+ (void *)var,
+ type ? type->tp_name : null_str,
+ var_str ? _PyUnicode_AsString(var_str) : "<error>");
+ if (var_str != NULL) {
+ Py_DECREF(var_str);
+ }
}
- fprintf(stderr, "\n");
}
void PyC_LineSpit(void)
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 25c88799027..fe7a046d99c 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -31,6 +31,7 @@
#include "BLI_utildefines_variadic.h"
void PyC_ObSpit(const char *name, PyObject *var);
+void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
PyObject * PyC_ExceptionBuffer(void);
@@ -50,12 +51,15 @@ int PyC_AsArray(
const PyTypeObject *type, const bool is_double, const char *error_prefix);
PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len);
+PyObject *PyC_Tuple_PackArray_F64(const double *array, uint len);
PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
#define PyC_Tuple_Pack_F32(...) \
PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_F64(...) \
+ PyC_Tuple_PackArray_F64(((const double []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32(...) \
PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32FromBool(...) \
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 2b6dc54dad4..ae16bd4a145 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -23,7 +23,7 @@
#
# ***** END GPL LICENSE BLOCK *****
-set(INC
+set(INC
..
../../blenkernel
../../blenlib
@@ -35,9 +35,10 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/cycles/blender
- ../../../../intern/opencolorio
+ ../../../../intern/clog
../../../../intern/guardedalloc
+ ../../../../intern/opencolorio
+ ../../../../intern/cycles/blender
)
set(INC_SYS
@@ -111,6 +112,7 @@ set(SRC
bpy_utils_units.h
gpu.h
../BPY_extern.h
+ ../BPY_extern_clog.h
)
# only to check if buildinfo is available
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index ae8e35ae3fc..99f87c61c5a 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -33,6 +33,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
#include "BLI_fileops.h"
@@ -75,6 +77,9 @@
#include "../bmesh/bmesh_py_api.h"
#include "../mathutils/mathutils.h"
+/* Logging types to use anywhere in the Python modules. */
+CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
+CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
/* for internal use, when starting and ending python scripts */
@@ -800,8 +805,9 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
CTX_data_list_add(result, ptr->id.data, ptr->type, ptr->data);
}
else {
- printf("PyContext: '%s' list item not a valid type in sequece type '%s'\n",
- member, Py_TYPE(item)->tp_name);
+ CLOG_INFO(BPY_LOG_CONTEXT, 1,
+ "'%s' list item not a valid type in sequence type '%s'",
+ member, Py_TYPE(item)->tp_name);
}
}
@@ -813,16 +819,14 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
if (done == false) {
if (item) {
- printf("PyContext '%s' not a valid type\n", member);
+ CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member);
}
else {
- printf("PyContext '%s' not found\n", member);
+ CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found\n", member);
}
}
else {
- if (G.debug & G_DEBUG_PYTHON) {
- printf("PyContext '%s' found\n", member);
- }
+ CLOG_INFO(BPY_LOG_CONTEXT, 2, "'%s' found", member);
}
if (use_gil)
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 87260d6e786..baaae066b4b 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BPY_extern.h"
+#include "BPY_extern_clog.h"
#include "bpy_rna.h"
#include "bpy_rna_anim.h"
@@ -61,6 +62,8 @@
#include "RNA_define.h" /* RNA_def_property_free_identifier */
#include "RNA_access.h"
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
#include "BKE_main.h"
@@ -1418,10 +1421,11 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
/* prefer not fail silently in case of api errors, maybe disable it later */
- printf("RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'\n",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
+ CLOG_WARN(BPY_LOG_RNA,
+ "current value '%d' "
+ "matches no enum in '%s', '%s', '%s'",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
#if 0 /* gives python decoding errors while generating docs :( */
char error_str[256];
@@ -6596,7 +6600,7 @@ static PyObject *pyrna_srna_ExternalType(StructRNA *srna)
if (bpy_types == NULL) {
PyErr_Print();
PyErr_Clear();
- fprintf(stderr, "%s: failed to find 'bpy_types' module\n", __func__);
+ CLOG_ERROR(BPY_LOG_RNA, "failed to find 'bpy_types' module");
return NULL;
}
bpy_types_dict = PyModule_GetDict(bpy_types); /* borrow */
@@ -6614,20 +6618,22 @@ static PyObject *pyrna_srna_ExternalType(StructRNA *srna)
PyObject *tp_slots = PyDict_GetItem(((PyTypeObject *)newclass)->tp_dict, bpy_intern_str___slots__);
if (tp_slots == NULL) {
- fprintf(stderr, "%s: expected class '%s' to have __slots__ defined\n\nSee bpy_types.py\n", __func__, idname);
+ CLOG_ERROR(BPY_LOG_RNA, "expected class '%s' to have __slots__ defined, see bpy_types.py", idname);
newclass = NULL;
}
else if (PyTuple_GET_SIZE(tp_bases)) {
PyObject *base = PyTuple_GET_ITEM(tp_bases, 0);
if (base_compare != base) {
- fprintf(stderr, "%s: incorrect subclassing of SRNA '%s'\nSee bpy_types.py\n", __func__, idname);
- PyC_ObSpit("Expected! ", base_compare);
+ char pyob_info[256];
+ PyC_ObSpitStr(pyob_info, sizeof(pyob_info), base_compare);
+ CLOG_ERROR(BPY_LOG_RNA,
+ "incorrect subclassing of SRNA '%s', expected '%s', see bpy_types.py",
+ idname, pyob_info);
newclass = NULL;
}
else {
- if (G.debug & G_DEBUG_PYTHON)
- fprintf(stderr, "SRNA Subclassed: '%s'\n", idname);
+ CLOG_INFO(BPY_LOG_RNA, 2, "SRNA sub-classed: '%s'", idname);
}
}
}
@@ -6725,7 +6731,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
}
else {
/* this should not happen */
- printf("%s: error registering '%s'\n", __func__, idname);
+ CLOG_ERROR(BPY_LOG_RNA, "failed to register '%s'", idname);
PyErr_Print();
PyErr_Clear();
}
@@ -6791,7 +6797,7 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr)
Py_DECREF(tp); /* srna owns, cant hold a ref */
}
else {
- fprintf(stderr, "%s: could not make type\n", __func__);
+ CLOG_WARN(BPY_LOG_RNA, "could not make type '%s'", RNA_struct_identifier(ptr->type));
pyrna = (BPy_StructRNA *) PyObject_GC_New(BPy_StructRNA, &pyrna_struct_Type);
#ifdef USE_WEAKREFS
pyrna->in_weakreflist = NULL;
@@ -7597,8 +7603,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
py_class = RNA_struct_py_type_get(ptr->type);
/* rare case. can happen when registering subclasses */
if (py_class == NULL) {
- fprintf(stderr, "%s: unable to get python class for rna struct '%.200s'\n",
- __func__, RNA_struct_identifier(ptr->type));
+ CLOG_WARN(BPY_LOG_RNA, "unable to get Python class for rna struct '%.200s'", RNA_struct_identifier(ptr->type));
return -1;
}
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index e0ca3634261..ed9d1e9c0e5 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -28,6 +28,8 @@
#include <Python.h>
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "RNA_types.h"
@@ -39,6 +41,8 @@
#include "RNA_access.h"
+#include "BPY_extern_clog.h"
+
#include "../generic/py_capi_utils.h"
#define USE_MATHUTILS
@@ -785,8 +789,7 @@ PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr,
len = RNA_property_multi_array_length(ptr, prop, arraydim);
if (index >= len || index < 0) {
/* this shouldn't happen because higher level funcs must check for invalid index */
- if (G.debug & G_DEBUG_PYTHON)
- printf("%s: invalid index %d for array with length=%d\n", __func__, index, len);
+ CLOG_WARN(BPY_LOG_RNA, "invalid index %d for array with length=%d", index, len);
PyErr_SetString(PyExc_IndexError, "out of range");
return NULL;
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 9492b6d67f3..026384743bd 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -689,6 +689,8 @@ PyDoc_STRVAR(euler_doc,
"\n"
" This object gives access to Eulers in Blender.\n"
"\n"
+" .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on Wikipedia.\n"
+"\n"
" :param angles: Three angles, in radians.\n"
" :type angles: 3d vector\n"
" :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index e17a503cd4e..67c87d5d9b8 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -84,6 +84,7 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -3349,7 +3350,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
if (!rr)
return false;
- bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+ bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
RE_HasFloatPixels(rr);
@@ -3466,7 +3467,7 @@ bool RE_WriteRenderViewsMovie(
if (!rr)
return false;
- is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+ is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
int view_id;
@@ -4067,7 +4068,7 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env,
/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
- switch (BLI_listbase_count_ex(&rr->layers, 2)) {
+ switch (BLI_listbase_count_at_most(&rr->layers, 2)) {
case 0:
return false;
case 1:
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 542c737348b..25377fb4f7e 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -753,7 +753,7 @@ void render_result_views_new(RenderResult *rr, RenderData *rd)
}
/* we always need at least one view */
- if (BLI_listbase_count_ex(&rr->views, 1) == 0) {
+ if (BLI_listbase_count_at_most(&rr->views, 1) == 0) {
render_result_view_new(rr, "");
}
}
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 9e877a83b3e..8be7555b34a 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -61,6 +61,7 @@
#include "wm.h"
#include "ED_screen.h"
+#include "BKE_undo_system.h"
#ifdef WITH_PYTHON
#include "BPY_extern.h"
@@ -485,7 +486,12 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
WM_drag_free_list(&wm->drags);
wm_reports_free(wm);
-
+
+ if (wm->undo_stack) {
+ BKE_undosys_stack_destroy(wm->undo_stack);
+ wm->undo_stack = NULL;
+ }
+
if (C && CTX_wm_manager(C) == wm) CTX_wm_manager_set(C, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index b2df53321c0..4f441c293c4 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -67,6 +67,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "RNA_access.h"
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index e0b57effbe9..da5ebd7abcd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -87,9 +87,11 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
+#include "BLO_undofile.h" /* to save from an undo memfile */
#include "RNA_access.h"
#include "RNA_define.h"
@@ -103,6 +105,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "GHOST_C-api.h"
#include "GHOST_Path-api.h"
@@ -522,9 +525,13 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
}
if (!G.background) {
-// undo_editmode_clear();
- BKE_undo_reset();
- BKE_undo_write(C, "original"); /* save current state */
+ if (wm->undo_stack == NULL) {
+ wm->undo_stack = BKE_undosys_stack_create();
+ }
+ else {
+ BKE_undosys_stack_clear(wm->undo_stack);
+ }
+ BKE_undosys_stack_init_from_main(wm->undo_stack, CTX_data_main(C));
}
}
@@ -596,10 +603,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
success = true;
}
-#if 0
- else if (retval == BKE_READ_EXOTIC_OK_OTHER)
- BKE_undo_write(C, "Import file");
-#endif
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -1271,7 +1274,10 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
if (U.uiflag & USER_GLOBALUNDO) {
/* fast save of last undobuffer, now with UI */
- BKE_undo_save_file(filepath);
+ struct MemFile *memfile = ED_undosys_stack_memfile_get_active(wm->undo_stack);
+ if (memfile) {
+ BLO_memfile_write_file(memfile, filepath);
+ }
}
else {
/* save as regular blend file */
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 2743216ee07..52682523212 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -55,6 +55,7 @@
#include "BLI_utildefines.h"
#include "BLO_writefile.h"
+#include "BLO_undofile.h"
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
@@ -112,6 +113,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "UI_interface.h"
#include "BLF_api.h"
@@ -149,11 +151,6 @@ static void wm_free_reports(bContext *C)
BKE_reports_clear(reports);
}
-static void wm_undo_kill_callback(bContext *C)
-{
- WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
-}
-
bool wm_start_with_console = false; /* used in creator.c */
/* only called once, for startup */
@@ -172,7 +169,7 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
- BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
+ ED_undosys_type_init();
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
@@ -478,7 +475,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
wmWindow *win;
if (!G.background) {
- if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) {
+ struct MemFile *undo_memfile = wm->undo_stack ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
+ if ((U.uiflag2 & USER_KEEP_SESSION) || (undo_memfile != NULL)) {
/* save the undo state as quit.blend */
char filename[FILE_MAX];
bool has_edited;
@@ -489,7 +487,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
has_edited = ED_editors_flush_edits(C, false);
if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) ||
- BKE_undo_save_file(filename))
+ (undo_memfile && BLO_memfile_write_file(undo_memfile, filename)))
{
printf("Saved session recovery to '%s'\n", filename);
}
@@ -512,11 +510,13 @@ void WM_exit_ext(bContext *C, const bool do_python)
wm_dropbox_free();
WM_menutype_free();
WM_uilisttype_free();
-
+
/* all non-screen and non-space stuff editors did, like editmode */
if (C)
ED_editors_exit(C);
+ ED_undosys_type_free();
+
// XXX
// BIF_GlobalReebFree();
// BIF_freeRetarget();
@@ -594,8 +594,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
GPU_exit();
}
- BKE_undo_reset();
-
ED_file_exit(); /* for fsmenu */
UI_exit();
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b05b2596719..f46358f83cf 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -96,7 +96,7 @@
#include "ED_numinput.h"
#include "ED_screen.h"
-#include "ED_util.h"
+#include "ED_undo.h"
#include "ED_view3d.h"
#include "GPU_basic_shader.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 0bfe62c7a8e..06bd60e8692 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -342,7 +342,7 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar
uiStyle *style = UI_style_get();
uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS);
- UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP );
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
UI_block_emboss_set(block, UI_EMBOSS);
uiLayout *layout = UI_block_layout(
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index d4af3cd6b09..1baae1864bf 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -715,16 +715,19 @@ static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(
static const char arg_handle_log_level_set_doc[] =
"<level>\n"
"\n"
-"\tSet the logging verbosity level (higher for more details) defaults to 1."
+"\tSet the logging verbosity level (higher for more details) defaults to 1, use -1 to log all levels."
;
static int arg_handle_log_level_set(int argc, const char **argv, void *UNUSED(data))
{
const char *arg_id = "--log-level";
if (argc > 1) {
const char *err_msg = NULL;
- if (!parse_int_clamp(argv[1], NULL, 0, INT_MAX, &G.log.level, &err_msg)) {
+ if (!parse_int_clamp(argv[1], NULL, -1, INT_MAX, &G.log.level, &err_msg)) {
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
}
+ if (G.log.level == -1) {
+ G.log.level = INT_MAX;
+ }
return 1;
}
else {
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index 81e6178c502..feb108da289 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -64,6 +64,7 @@
#include "BKE_main.h"
#include "BKE_report.h"
+
/* for passing information between creator and gameengine */
#ifdef WITH_GAMEENGINE
# include "BL_System.h"
@@ -75,6 +76,12 @@
#include "creator_intern.h" /* own include */
+// #define USE_WRITE_CRASH_BLEND
+#ifdef USE_WRITE_CRASH_BLEND
+# include "BKE_undo_system.h"
+# include "BLO_undofile.h"
+#endif
+
/* set breakpoints here when running in debug mode, useful to catch floating point errors */
#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
static void sig_handle_fpe(int UNUSED(sig))
@@ -110,29 +117,32 @@ static void sig_handle_crash_backtrace(FILE *fp)
static void sig_handle_crash(int signum)
{
+ wmWindowManager *wm = G.main->wm.first;
-#if 0
- {
- char fname[FILE_MAX];
+#ifdef USE_WRITE_CRASH_BLEND
+ if (wm->undo_stack) {
+ struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
+ if (memfile) {
+ char fname[FILE_MAX];
- if (!G.main->name[0]) {
- BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
- }
- else {
- BLI_strncpy(fname, G.main->name, sizeof(fname));
- BLI_replace_extension(fname, sizeof(fname), ".crash.blend");
- }
+ if (!G.main->name[0]) {
+ BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
+ }
+ else {
+ BLI_strncpy(fname, G.main->name, sizeof(fname));
+ BLI_replace_extension(fname, sizeof(fname), ".crash.blend");
+ }
- printf("Writing: %s\n", fname);
- fflush(stdout);
+ printf("Writing: %s\n", fname);
+ fflush(stdout);
- BKE_undo_save_file(fname);
+ BLO_memfile_write_file(memfile, fname);
+ }
}
#endif
FILE *fp;
char header[512];
- wmWindowManager *wm = G.main->wm.first;
char fname[FILE_MAX];
@@ -338,4 +348,4 @@ void main_signal_setup_fpe(void)
#endif
}
-#endif /* WITH_PYTHON_MODULE */ \ No newline at end of file
+#endif /* WITH_PYTHON_MODULE */
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 8ba39e288ca..a12437befaa 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -1540,7 +1540,7 @@ static KX_GameObject *gameobject_from_blenderobject(
gameobj->AddMesh(meshobj);
// gather levels of detail
- if (BLI_listbase_count_ex(&ob->lodlevels, 2) > 1) {
+ if (BLI_listbase_count_at_most(&ob->lodlevels, 2) > 1) {
LodLevel *lod = ((LodLevel*)ob->lodlevels.first)->next;
Mesh* lodmesh = mesh;
Object* lodmatob = ob;