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:
authorCampbell Barton <ideasman42@gmail.com>2018-04-01 12:03:25 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-04-01 12:03:25 +0300
commitb65ea517eb932bde950bde51979c6a3fd258efa8 (patch)
tree8f3a291a7e1778bb3af45cdb1d98a621efbd1a7d
parent916c91bd08933d596eaca3e369467daf7964612e (diff)
parent473f17b3d557adbb06b89e0a186be48a0129086d (diff)
Merge branch 'master' into blender2.8
- Undo that changes modes currently asserts, since undo is now screen data. Most likely we will change how object mode and workspaces work since it's not practical/maintainable at the moment. - Removed view_layer from particle settings (wasn't needed and complicated undo).
-rw-r--r--build_files/build_environment/cmake/sndfile.cmake2
-rwxr-xr-xbuild_files/build_environment/install_deps.sh2
-rw-r--r--build_files/cmake/macros.cmake4
-rw-r--r--doc/doxygen/doxygen.intern.h4
-rw-r--r--doc/python_api/examples/bge.texture.py19
-rw-r--r--doc/python_api/rst/bge.texture.rst141
-rw-r--r--intern/CMakeLists.txt1
-rw-r--r--intern/clog/CLG_log.h211
-rw-r--r--intern/clog/CMakeLists.txt34
-rw-r--r--intern/clog/clog.c583
-rw-r--r--source/blender/blenfont/intern/blf.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c4
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c111
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h28
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h17
-rw-r--r--source/blender/blenkernel/BKE_global.h7
-rw-r--r--source/blender/blenkernel/BKE_main.h6
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h6
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h187
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/intern/armature.c1
-rw-r--r--source/blender/blenkernel/intern/armature_update.c1
-rw-r--r--source/blender/blenkernel/intern/blender.c6
-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/fluidsim.c1
-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.c2
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c1
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1
-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/texture.c1
-rw-r--r--source/blender/blenkernel/intern/undo_system.c795
-rw-r--r--source/blender/blenkernel/intern/world.c1
-rw-r--r--source/blender/blenlib/BLI_sort_utils.h7
-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.c4
-rw-r--r--source/blender/blenloader/intern/undofile.c78
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c2
-rw-r--r--source/blender/editors/armature/editarmature_undo.c120
-rw-r--r--source/blender/editors/curve/editcurve.c3
-rw-r--r--source/blender/editors/curve/editcurve_undo.c161
-rw-r--r--source/blender/editors/curve/editfont_undo.c123
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1
-rw-r--r--source/blender/editors/include/ED_armature.h6
-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.h1
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h13
-rw-r--r--source/blender/editors/include/ED_sculpt.h6
-rw-r--r--source/blender/editors/include/ED_text.h7
-rw-r--r--source/blender/editors/include/ED_util.h17
-rw-r--r--source/blender/editors/io/io_cache.c1
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c121
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c1
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c135
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c1
-rw-r--r--source/blender/editors/metaball/editmball_undo.c117
-rw-r--r--source/blender/editors/object/object_modes.c42
-rw-r--r--source/blender/editors/physics/particle_edit.c92
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c256
-rw-r--r--source/blender/editors/physics/particle_object.c8
-rw-r--r--source/blender/editors/physics/physics_fluid.c3
-rw-r--r--source/blender/editors/physics/physics_intern.h3
-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.c5
-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.c162
-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.c163
-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_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c173
-rw-r--r--source/blender/editors/space_action/action_buttons.c1
-rw-r--r--source/blender/editors/space_action/action_data.c1
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c1
-rw-r--r--source/blender/editors/space_image/image_ops.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c1
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_text/text_ops.c70
-rw-r--r--source/blender/editors/space_text/text_undo.c169
-rw-r--r--source/blender/editors/transform/transform_conversions.c8
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c2
-rw-r--r--source/blender/editors/util/CMakeLists.txt4
-rw-r--r--source/blender/editors/util/ed_util.c18
-rw-r--r--source/blender/editors/util/editmode_undo.c373
-rw-r--r--source/blender/editors/util/memfile_undo.c149
-rw-r--r--source/blender/editors/util/undo.c327
-rw-r--r--source/blender/editors/util/undo_system_types.c74
-rw-r--r--source/blender/editors/util/util_intern.h14
-rw-r--r--source/blender/imbuf/intern/anim_movie.c1
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c1
-rw-r--r--source/blender/imbuf/intern/util.c1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c1
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c1
-rw-r--r--source/blender/physics/intern/implicit_blender.c1
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_types.h8
-rw-r--r--source/blender/windowmanager/WM_undo.h0
-rw-r--r--source/blender/windowmanager/intern/wm.c8
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c89
-rw-r--r--source/blender/windowmanager/intern/wm_files.c17
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c28
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c12
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c32
-rw-r--r--source/creator/CMakeLists.txt1
-rw-r--r--source/creator/creator.c12
-rw-r--r--source/creator/creator_args.c121
-rw-r--r--source/creator/creator_signals.c40
-rw-r--r--source/gameengine/Ketsji/KX_FontObject.cpp2
134 files changed, 4287 insertions, 2227 deletions
diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake
index 282033d4905..2c4da159280 100644
--- a/build_files/build_environment/cmake/sndfile.cmake
+++ b/build_files/build_environment/cmake/sndfile.cmake
@@ -27,7 +27,7 @@ else()
set(SNDFILE_OPTIONS --enable-static --disable-shared )
endif()
-if(APPLE)
+if(UNIX)
set(SNDFILE_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/sndfile/src/external_sndfile < ${PATCH_DIR}/sndfile.diff)
else()
set(SNDFILE_PATCH_CMD)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index c1ba2a3ab25..c474c39d910 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -1650,7 +1650,6 @@ compile_OIIO() {
cmake_d="$cmake_d -D LINKSTATIC=OFF"
cmake_d="$cmake_d -D USE_SIMD=sse2"
- cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
if [ "$_with_built_openexr" = true ]; then
@@ -1669,6 +1668,7 @@ compile_OIIO() {
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
+ cmake_d="$cmake_d -D TXT2MAN="
#cmake_d="$cmake_d -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
#cmake_d="$cmake_d -D CMAKE_VERBOSE_MAKEFILE=ON"
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 64ff4fc3aff..dfac6d1798e 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -565,6 +565,9 @@ function(SETUP_BLENDER_SORTED_LIBS)
set(BLENDER_SORTED_LIBS
bf_windowmanager
+ # needed twice because of text undo
+ bf_editor_util
+
bf_editor_space_api
bf_editor_space_action
bf_editor_space_buttons
@@ -689,6 +692,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
extern_sdlew
bf_intern_glew_mx
+ bf_intern_clog
)
if(NOT WITH_SYSTEM_GLOG)
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index e3cc11b3404..777f35ef50a 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -10,6 +10,10 @@
* \ingroup intern
*/
+/** \defgroup clog C-Logging (CLOG)
+ * \ingroup intern
+ */
+
/** \defgroup ctr container
* \ingroup intern
*/
diff --git a/doc/python_api/examples/bge.texture.py b/doc/python_api/examples/bge.texture.py
index ac1f5a21447..8b24530b10a 100644
--- a/doc/python_api/examples/bge.texture.py
+++ b/doc/python_api/examples/bge.texture.py
@@ -1,8 +1,11 @@
"""
Basic Video Playback
++++++++++++++++++++
-Example of how to replace a texture in game with a video. It needs to run
-everyframe.
+Example of how to replace a texture in game with a video.
+It needs to run everyframe.
+To avoid any confusion with the location of the file,
+we will use ``GameLogic.expandPath()`` to build an absolute file name,
+assuming the video file is in the same directory as the blend-file.
"""
import bge
from bge import texture
@@ -26,8 +29,18 @@ if not hasattr(logic, 'video'):
logic.video.source = texture.VideoFFmpeg(movie)
logic.video.source.scale = True
+ # Note that we can change the ``Texture`` source at any time.
+ # Suppose we want to switch between two movies during the game:
+ logic.mySources[0] = texture.VideoFFmpeg('movie1.avi')
+ logic.mySources[1] = texture.VideoFFmpeg('movie2.avi')
+
+ #And then assign (and reassign) the source during the game
+ logic.video.source = logic.mySources[movieSel]
+
# quick off the movie, but it wont play in the background
logic.video.source.play()
-# you need to call this function every frame to ensure update of the texture.
+
+# Video playback is not a background process: it happens only when we refresh the texture.
+# So you need to call this function every frame to ensure update of the texture.
logic.video.refresh(True)
diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst
index 3028ee653f8..cd99cde0bc8 100644
--- a/doc/python_api/rst/bge.texture.rst
+++ b/doc/python_api/rst/bge.texture.rst
@@ -6,18 +6,15 @@ Video Texture (bge.texture)
Introduction
************
-The bge.texture module allows you to manipulate textures during the game.
-
-Several sources for texture are possible: video files, image files, video capture, memory buffer,
-camera render or a mix of that.
-
-The video and image files can be loaded from the internet using an URL instead of a file name.
-
-In addition, you can apply filters on the images before sending them to the GPU, allowing video effect:
-blue screen, color band, gray, normal map.
-
-bge.texture uses FFmpeg to load images and videos.
-All the formats and codecs that FFmpeg supports are supported by this module, including but not limited to:
+The ``bge.texture`` module allows you to manipulate textures during the game.
+Several sources for texture are possible: video files, image files, video capture,
+memory buffer, camera render or a mix of that.
+The video and image files can be loaded from the Internet using a URL instead of a file name.
+In addition, you can apply filters on the images before sending them to the GPU,
+allowing video effect: blue screen, color band, gray, normal map.
+``bge.texture`` uses FFmpeg to load images and videos.
+All the formats and codecs that FFmpeg supports are supported by ``bge.texture``,
+including but not limited to:
* AVI
* Ogg
@@ -28,16 +25,45 @@ All the formats and codecs that FFmpeg supports are supported by this module, in
* videoForWindows capture card (this includes many webcams)
* JPG
-The principle is simple: first you identify a texture on an existing object using
-the :class:`~bge.texture.materialID` function, then you create a new texture with dynamic content
+
+How it works
+------------
+
+The principle is simple: first you identify a texture on an existing object using the
+:class:`~bge.texture.materialID` function, then you create a new texture with dynamic content
and swap the two textures in the GPU.
-The GE is not aware of the substitution and continues to display the object as always,
+The game engine is not aware of the substitution and continues to display the object as always,
except that you are now in control of the texture.
When the texture object is deleted, the new texture is deleted and the old texture restored.
-.. module:: bge.texture
+
+Game Preparation
+----------------
+
+Before you can use the :mod:`bge.texture` module,
+you must have objects with textures applied appropriately.
+
+Imagine you want to have a television showing live broadcast programs in the game.
+You will create a television object and UV-apply a different texture at the place of the screen,
+for example ``tv.png``. What this texture looks like is not important;
+probably you want to make it dark gray to simulate power-off state.
+When the television must be turned on, you create a dynamic texture from a video capture card
+and use it instead of ``tv.png``: the TV screen will come to life.
+
+You have two ways to define textures that ``bge.texture`` can grab:
+
+- Simple UV texture.
+- Blender material with image texture channel.
+
+Because ``bge.texture`` works at texture level, it is compatible with all
+the Blender Game Engine's fancy texturing features: GLSL, multi-texture, custom shaders, etc.
+
+
+********
+Examples
+********
.. include:: __/examples/bge.texture.py
:start-line: 1
@@ -53,7 +79,6 @@ When the texture object is deleted, the new texture is deleted and the old textu
.. literalinclude:: __/examples/bge.texture.1.py
:lines: 8-
-
.. include:: __/examples/bge.texture.2.py
:start-line: 1
:end-line: 6
@@ -62,13 +87,15 @@ When the texture object is deleted, the new texture is deleted and the old textu
:lines: 8-
+.. module:: bge.texture
+
*************
Video classes
*************
.. class:: VideoFFmpeg(file, capture=-1, rate=25.0, width=0, height=0)
- FFmpeg video source.
+ FFmpeg video source, used for video files, video captures, or video streams.
:arg file: Path to the video to load; if capture >= 0 on Windows, this parameter will not be used.
:type file: str
@@ -90,19 +117,20 @@ Video classes
.. attribute:: range
- Replay range.
+ The start and stop time of the video playback, expressed in seconds from beginning.
+ By default the entire video.
:type: sequence of two floats
.. attribute:: repeat
- Repeat count, -1 for infinite repeat.
+ Number of times to replay the video, -1 for infinite repeat.
:type: int
.. attribute:: framerate
- Frame rate.
+ Relative frame rate, <1.0 for slow, >1.0 for fast.
:type: float
@@ -126,21 +154,26 @@ Video classes
.. attribute:: scale
- Fast scale of image (near neighbour).
+ Set to True to activate fast nearest neighbor scaling algorithm.
+ Texture width and height must be a power of 2.
+ If the video picture size is not a power of 2, rescaling is required.
+ By default ``bge.texture`` uses the precise but slow ``gluScaleImage()`` function.
+ Best is to rescale the video offline so that no scaling is necessary at runtime!
:type: bool
.. attribute:: flip
- Flip image vertically.
+ If True the imaged will be flipped vertically.
+ FFmpeg always delivers the image upside down, so this attribute is set to True by default.
:type: bool
.. attribute:: filter
- Pixel filter.
+ An additional filter that is applied on the video before sending it to the GPU.
- :type: one of...
+ :type: one of:
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
@@ -207,7 +240,7 @@ Image classes
.. class:: ImageFFmpeg(file)
- FFmpeg image source.
+ FFmpeg image source, used for image files and web based images.
:arg file: Path to the image to load.
:type file: str
@@ -286,7 +319,8 @@ Image classes
.. class:: ImageBuff(width, height, color=0, scale=False)
- Image source from image buffer.
+ Image from application memory.
+ For computer generated images, drawing applications.
:arg width: Width of the image.
:type width: int
@@ -477,7 +511,7 @@ Image classes
.. class:: ImageMix
- Image mixer.
+ Image mixer used to mix multiple image sources together.
.. attribute:: filter
@@ -592,7 +626,7 @@ Image classes
.. class:: ImageRender(scene, camera)
- Image source from render.
+ Image source from a render of a non active camera.
The render is done on a custom framebuffer object if fbo is specified,
otherwise on the default framebuffer.
@@ -723,7 +757,8 @@ Image classes
.. class:: ImageViewport
- Image source from viewport.
+ Image source from viewport rendered by the active camera.
+ To render from a non active camera see :class:`ImageRender`.
.. attribute:: alpha
@@ -774,11 +809,10 @@ Image classes
Refresh video - copy the viewport to an external buffer (optional) then invalidate its current content.
- :arg buffer: An optional object that implements the buffer protocol.
- If specified, the image is copied to the buffer, which must be big enough or an exception is thrown.
- The transfer to the buffer is optimal if no processing of the image is needed.
- This is the case if ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False``
- and no filter is set.
+ :arg buffer: An optional object that implements the buffer protocol. If specified,
+ the image is copied to the buffer, which must be big enough or an exception is thrown.
+ The transfer to the buffer is optimal if no processing of the image is needed. This is the case if
+ ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False`` and no filter is set.
:type buffer: any buffer type
:arg format: An optional image format specifier for the image that will be copied to the buffer.
Only valid values are "RGBA" or "BGRA"
@@ -838,18 +872,16 @@ Image classes
:arg capture: Card number from which the input video must be captured.
:type capture: int
- The format argument must be written as ``<displayMode>/<pixelFormat>[/3D][:<cacheSize>]`` where ``<displayMode>``
- describes the frame size and rate and <pixelFormat> the encoding of the pixels.
+ The format argument must be written as ``<displayMode>/<pixelFormat>[/3D][:<cacheSize>]``
+ where ``<displayMode>`` describes the frame size and rate and <pixelFormat> the encoding of the pixels.
The optional ``/3D`` suffix is to be used if the video stream is stereo with a left and right eye feed.
The optional ``:<cacheSize>`` suffix determines the number of the video frames kept in cache, by default 8.
- Some DeckLink cards won't work below a certain cache size.
- The default value 8 should be sufficient for all cards.
+ Some DeckLink cards won't work below a certain cache size. The default value 8 should be sufficient for all cards.
You may try to reduce the cache size to reduce the memory footprint. For example the The 4K Extreme is known
to work with 3 frames only, the Extreme 2 needs 4 frames and the Intensity Shuttle needs 6 frames, etc.
Reducing the cache size may be useful when Decklink is used in conjunction with GPUDirect:
all frames must be locked in memory in that case and that puts a lot of pressure on memory.
- If you reduce the cache size too much,
- you'll get no error but no video feed either.
+ If you reduce the cache size too much, you'll get no error but no video feed either.
The valid ``<displayMode>`` values are copied from the ``BMDDisplayMode`` enum in the DeckLink API
without the 'bmdMode' prefix. In case a mode that is not in this list is added in a later version
@@ -1006,15 +1038,20 @@ Texture classes
.. class:: Texture(gameObj, materialID=0, textureID=0, textureObj=None)
- Texture object.
+ Class that creates the ``Texture`` object that loads the dynamic texture on the GPU.
:arg gameObj: Game object to be created a video texture on.
:type gameObj: :class:`~bge.types.KX_GameObject`
- :arg materialID: Material ID. (optional)
+ :arg materialID: Material ID default, 0 is the first material. (optional)
:type materialID: int
- :arg textureID: Texture ID. (optional)
+ :arg textureID: Texture index in case of multi-texture channel, 0 = first channel by default.
+ In case of UV texture, this parameter should always be 0. (optional)
:type textureID: int
- :arg textureObj: Texture object with shared bindId. (optional)
+ :arg textureObj: Reference to another ``Texture`` object with shared bindId
+ which he user might want to reuse the texture.
+ If this argument is used, you should not create any source on this texture
+ and there is no need to refresh it either: the other ``Texture`` object will
+ provide the texture for both materials/textures.(optional)
:type textureObj: :class:`Texture`
.. attribute:: bindId
@@ -1094,7 +1131,7 @@ Texture classes
.. attribute:: source
- This attribute must be set to one of the image source. If the image size does not fit exactly
+ This attribute must be set to one of the image sources. If the image size does not fit exactly
the frame size, the extend attribute determines what to do.
For best performance, the source image should match exactly the size of the output frame.
@@ -1368,7 +1405,7 @@ Functions
Returns a :class:`~bgl.Buffer` corresponding to the current image stored in a texture source object.
- :arg image: Image source object of type ...
+ :arg image: Image source object of type:
* :class:`VideoFFmpeg`
* :class:`ImageFFmpeg`
@@ -1387,7 +1424,7 @@ Functions
- "BGR" will return 3 bytes per pixel with the
Blue, Green and Red channels in that order.
- - "RGB1" will return 4 bytes per pixel with the
+ - "RGB1" will return 4 bytes per pixel with the
Red, Green, Blue channels in that order and the alpha channel forced to 255.
- A special mode "F" allows to return the image as an array of float.
@@ -1429,9 +1466,10 @@ Functions
.. function:: setLogFile(filename)
- Sets the name of a text file in which runtime error messages will be written, in addition to the printing
- of the messages on the Python console. Only the runtime errors specific to the VideoTexture module
- are written in that file, ordinary runtime time errors are not written.
+ Sets the name of a text file in which runtime error messages will be written,
+ in addition to the printing of the messages on the Python console.
+ Only the runtime errors specific to the VideoTexture module are written in that file,
+ ordinary runtime time errors are not written.
:arg filename: Name of the error log file.
:type filename: str
@@ -1517,4 +1555,3 @@ See Wikipedia's `Blend Modes <https://en.wikipedia.org/wiki/Blend_modes>`_ for r
.. data:: IMB_BLEND_COPY_RGB
.. data:: IMB_BLEND_COPY_ALPHA
-
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index af3b9296077..4b3ccfc808a 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -24,6 +24,7 @@
# ***** END GPL LICENSE BLOCK *****
# add_subdirectory(atomic) # header only
+add_subdirectory(clog)
add_subdirectory(string)
add_subdirectory(ghost)
add_subdirectory(guardedalloc)
diff --git a/intern/clog/CLG_log.h b/intern/clog/CLG_log.h
new file mode 100644
index 00000000000..8afa9edd75b
--- /dev/null
+++ b/intern/clog/CLG_log.h
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __CLOG_H__
+#define __CLOG_H__
+
+/** \file clog/CLG_log.h
+ * \ingroup clog
+ *
+ * C Logging Library (clog)
+ * ========================
+ *
+ * Usage
+ * -----
+ *
+ * - `CLG_LOGREF_DECLARE_GLOBAL` macro to declare #CLG_LogRef pointers.
+ * - `CLOG_` prefixed macros for logging.
+ *
+ * Identifiers
+ * -----------
+ *
+ * #CLG_LogRef holds an identifier which defines the category of the logger.
+ *
+ * You can define and use identifiers as needed, logging will lazily initialize them.
+ *
+ * By convention lower case dot separated identifiers are used, eg:
+ * `module.sub_module`, this allows filtering by `module.*`,
+ * see #CLG_type_filter_include, #CLG_type_filter_exclude
+ *
+ * There is currently no functionality to remove a category once it's created.
+ *
+ * Severity
+ * --------
+ *
+ * - `INFO`: Simply log events, uses verbosity levels to control how much information to show.
+ * - `WARN`: General warnings (which aren't necessary to show to users).
+ * - `ERROR`: An error we can recover from, should not happen.
+ * - `FATAL`: Similar to assert. This logs the message, then a stack trace and abort.
+ *
+ *
+ * Verbosity Level
+ * ---------------
+ *
+ * Usage:
+ *
+ * - 0: Always show (used for warnings, errors).
+ * Should never get in the way or become annoying.
+ *
+ * - 1: Top level module actions (eg: load a file, create a new window .. etc).
+ *
+ * - 2: Actions within a module (steps which compose an action, but don't flood output).
+ * Running a tool, full data recalculation.
+ *
+ * - 3: Detailed actions which may be of interest when debugging internal logic of a module
+ * These *may* flood the log with details.
+ *
+ * - 4+: May be used for more details than 3, should be avoided but not prevented.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef __GNUC__
+# define _CLOG_ATTR_NONNULL(args ...) __attribute__((nonnull(args)))
+#else
+# define _CLOG_ATTR_NONNULL(...)
+#endif
+
+#ifdef __GNUC__
+# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) __attribute__((format(printf, format_param, dots_param)))
+#else
+# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+#if defined(_MSC_VER) && !defined(__func__)
+# define __func__MSVC
+# define __func__ __FUNCTION__
+#endif
+
+#define STRINGIFY_ARG(x) "" #x
+#define STRINGIFY_APPEND(a, b) "" a #b
+#define STRINGIFY(x) STRINGIFY_APPEND("", x)
+
+struct CLogContext;
+
+/* Don't typedef enums. */
+enum CLG_LogFlag {
+ CLG_FLAG_USE = (1 << 0),
+};
+
+enum CLG_Severity {
+ CLG_SEVERITY_INFO = 0,
+ CLG_SEVERITY_WARN,
+ CLG_SEVERITY_ERROR,
+ CLG_SEVERITY_FATAL,
+};
+#define CLG_SEVERITY_LEN (CLG_SEVERITY_FATAL + 1)
+
+/* Each logger ID has one of these. */
+typedef struct CLG_LogType {
+ struct CLG_LogType *next;
+ char identifier[64];
+ /** FILE output. */
+ struct CLogContext *ctx;
+ /** Control behavior. */
+ int level;
+ enum CLG_LogFlag flag;
+} CLG_LogType;
+
+typedef struct CLG_LogRef {
+ const char *identifier;
+ CLG_LogType *type;
+} CLG_LogRef;
+
+void CLG_log_str(
+ CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
+ const char *message)
+ _CLOG_ATTR_NONNULL(1, 3, 4, 5);
+void CLG_logf(
+ CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
+ const char *format, ...)
+ _CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6);
+
+/* Main initializer and distructor (per session, not logger). */
+void CLG_init(void);
+void CLG_exit(void);
+
+void CLG_output_set(void *file_handle);
+void CLG_output_use_basename_set(int value);
+void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle));
+
+void CLG_type_filter_include(const char *type_filter, int type_filter_len);
+void CLG_type_filter_exclude(const char *type_filter, int type_filter_len);
+
+void CLG_logref_init(CLG_LogRef *clg_ref);
+
+/** Declare outside function, declare as extern in header. */
+#define CLG_LOGREF_DECLARE_GLOBAL(var, id) \
+ static CLG_LogRef _static_ ## var = {id}; \
+ CLG_LogRef *var = &_static_ ## var
+
+/** Initialize struct once. */
+#define CLOG_ENSURE(clg_ref) \
+ ((clg_ref)->type ? (clg_ref)->type : (CLG_logref_init(clg_ref), (clg_ref)->type))
+
+#define CLOG_AT_SEVERITY(clg_ref, severity, verbose_level, ...) { \
+ CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
+ if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
+ CLG_logf(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \
+ } \
+} ((void)0)
+
+#define CLOG_STR_AT_SEVERITY(clg_ref, severity, verbose_level, str) { \
+ CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
+ if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
+ CLG_log_str(lg, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \
+ } \
+} ((void)0)
+
+#define CLOG_STR_AT_SEVERITY_N(clg_ref, severity, verbose_level, str) { \
+ CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
+ if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
+ const char *_str = str; \
+ CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, _str); \
+ MEM_freeN((void *)_str); \
+ } \
+} ((void)0)
+
+#define CLOG_INFO(clg_ref, level, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
+#define CLOG_WARN(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
+#define CLOG_ERROR(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
+#define CLOG_FATAL(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
+
+#define CLOG_STR_INFO(clg_ref, level, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
+#define CLOG_STR_WARN(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
+#define CLOG_STR_ERROR(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
+#define CLOG_STR_FATAL(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
+
+/* Allocated string which is immediately freed. */
+#define CLOG_STR_INFO_N(clg_ref, level, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
+#define CLOG_STR_WARN_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
+#define CLOG_STR_ERROR_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
+#define CLOG_STR_FATAL_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
+
+#ifdef __func__MSVC
+# undef __func__MSVC
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CLOG_H__ */
diff --git a/intern/clog/CMakeLists.txt b/intern/clog/CMakeLists.txt
new file mode 100644
index 00000000000..8bf7b66f7ec
--- /dev/null
+++ b/intern/clog/CMakeLists.txt
@@ -0,0 +1,34 @@
+# ***** 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 *****
+
+set(INC
+ .
+ ../guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ clog.c
+
+ CLG_log.h
+)
+
+blender_add_lib(bf_intern_clog "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
new file mode 100644
index 00000000000..dfbd34d341a
--- /dev/null
+++ b/intern/clog/clog.c
@@ -0,0 +1,583 @@
+/*
+ * ***** 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 clog/clog.c
+ * \ingroup clog
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+/* For 'isatty' to check for color. */
+#if defined(__unix__)
+# include <unistd.h>
+#endif
+
+/* Only other dependency (could use regular malloc too). */
+#include "MEM_guardedalloc.h"
+
+/* own include. */
+#include "CLG_log.h"
+
+/* Local utility defines */
+#define STREQ(a, b) (strcmp(a, b) == 0)
+#define STREQLEN(a, b, n) (strncmp(a, b, n) == 0)
+
+#ifdef _WIN32
+# define PATHSEP_CHAR '\\'
+#else
+# define PATHSEP_CHAR '/'
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
+typedef struct CLG_IDFilter {
+ struct CLG_IDFilter *next;
+ /** Over alloc. */
+ char match[0];
+} CLG_IDFilter;
+
+typedef struct CLogContext {
+ /** Single linked list of types. */
+ CLG_LogType *types;
+ /* exclude, include filters. */
+ CLG_IDFilter *filters[2];
+ bool use_color;
+ bool use_basename;
+
+ /** Borrowed, not owned. */
+ FILE *output;
+
+ /** For new types. */
+ struct {
+ int level;
+ } default_type;
+
+ struct {
+ void (*fatal_fn)(void *file_handle);
+ } callbacks;
+} CLogContext;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mini Buffer Functionality
+ *
+ * Use so we can do a single call to write.
+ * \{ */
+
+#define CLOG_BUF_LEN_INIT 512
+
+typedef struct CLogStringBuf {
+ char *data;
+ uint len;
+ uint len_alloc;
+ bool is_alloc;
+} CLogStringBuf;
+
+static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
+{
+ cstr->data = buf_stack;
+ cstr->len_alloc = buf_stack_len;
+ cstr->len = 0;
+ cstr->is_alloc = false;
+}
+
+static void clg_str_free(CLogStringBuf *cstr)
+{
+ if (cstr->is_alloc) {
+ MEM_freeN(cstr->data);
+ }
+}
+
+static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
+{
+ if (len > cstr->len_alloc) {
+ cstr->len_alloc *= 2;
+ if (len > cstr->len_alloc) {
+ cstr->len_alloc = len;
+ }
+
+ if (cstr->is_alloc) {
+ cstr->data = MEM_reallocN(cstr->data, cstr->len_alloc);
+ }
+ else {
+ /* Copy the static buffer. */
+ char *data = MEM_mallocN(cstr->len_alloc, __func__);
+ memcpy(data, cstr->data, cstr->len);
+ cstr->data = data;
+ cstr->is_alloc = true;
+ }
+ cstr->len_alloc = len;
+ }
+}
+
+static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
+{
+ uint len_next = cstr->len + len;
+ clg_str_reserve(cstr, len_next);
+ char *str_dst = cstr->data + cstr->len;
+ memcpy(str_dst, str, len);
+#if 0 /* no need. */
+ str_dst[len] = '\0';
+#endif
+ cstr->len = len_next;
+}
+
+static void clg_str_append(CLogStringBuf *cstr, const char *str)
+{
+ clg_str_append_with_len(cstr, str, strlen(str));
+}
+
+static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
+{
+ /* Use limit because windows may use '-1' for a formatting error. */
+ const uint len_max = 65535;
+ uint len_avail = (cstr->len_alloc - cstr->len);
+ if (len_avail == 0) {
+ len_avail = CLOG_BUF_LEN_INIT;
+ clg_str_reserve(cstr, len_avail);
+ }
+ while (true) {
+ va_list args_cpy;
+ va_copy(args_cpy, args);
+ int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
+ va_end(args_cpy);
+ if (retval != -1) {
+ cstr->len += retval;
+ break;
+ }
+ else {
+ len_avail *= 2;
+ if (len_avail >= len_max) {
+ break;
+ }
+ clg_str_reserve(cstr, len_avail);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+enum eCLogColor {
+ COLOR_DEFAULT,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW,
+
+ COLOR_RESET,
+};
+#define COLOR_LEN (COLOR_RESET + 1)
+
+static const char *clg_color_table[COLOR_LEN] = {NULL};
+
+static void clg_color_table_init(bool use_color)
+{
+ for (int i = 0; i < COLOR_LEN; i++) {
+ clg_color_table[i] = "";
+ }
+ if (use_color) {
+#ifdef _WIN32
+ /* TODO */
+#else
+ clg_color_table[COLOR_DEFAULT] = "\033[1;37m";
+ clg_color_table[COLOR_RED] = "\033[1;31m";
+ clg_color_table[COLOR_GREEN] = "\033[1;32m";
+ clg_color_table[COLOR_YELLOW] = "\033[1;33m";
+ clg_color_table[COLOR_RESET] = "\033[0m";
+#endif
+ }
+}
+
+static const char *clg_severity_str[CLG_SEVERITY_LEN] = {
+ [CLG_SEVERITY_INFO] = "INFO",
+ [CLG_SEVERITY_WARN] = "WARN",
+ [CLG_SEVERITY_ERROR] = "ERROR",
+ [CLG_SEVERITY_FATAL] = "FATAL",
+};
+
+static const char *clg_severity_as_text(enum CLG_Severity severity)
+{
+ bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
+ assert(ok);
+ if (ok) {
+ return clg_severity_str[severity];
+ }
+ else {
+ return "INVALID_SEVERITY";
+ }
+}
+
+static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
+{
+ assert((unsigned int)severity < CLG_SEVERITY_LEN);
+ enum eCLogColor color = COLOR_DEFAULT;
+ switch (severity) {
+ case CLG_SEVERITY_INFO:
+ color = COLOR_DEFAULT;
+ break;
+ case CLG_SEVERITY_WARN:
+ color = COLOR_YELLOW;
+ break;
+ case CLG_SEVERITY_ERROR:
+ case CLG_SEVERITY_FATAL:
+ color = COLOR_RED;
+ break;
+ default:
+ /* should never get here. */
+ assert(false);
+ }
+ return color;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Type Access
+ * \{ */
+
+/**
+ * Filter the indentifier based on very basic globbing.
+ * - `foo` exact match of `foo`.
+ * - `foo.bar` exact match for `foo.bar`
+ * - `foo.*` match for `foo` & `foo.bar` & `foo.bar.baz`
+ * - `*` matches everything.
+ */
+static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
+{
+ const int identifier_len = strlen(identifier);
+ for (uint i = 0; i < 2; i++) {
+ const CLG_IDFilter *flt = ctx->filters[i];
+ while (flt != NULL) {
+ const int len = strlen(flt->match);
+ if (STREQ(flt->match, "*") ||
+ ((len == identifier_len) && (STREQ(identifier, flt->match))))
+ {
+ return (bool)i;
+ }
+ if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
+ if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) ||
+ ((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1)))
+ {
+ return (bool)i;
+ }
+ }
+ flt = flt->next;
+ }
+ }
+ return false;
+}
+
+/**
+ * \note This should never be called per logging call.
+ * Searching is only to get an initial handle.
+ */
+static CLG_LogType *clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
+{
+ for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
+ if (STREQ(identifier, ty->identifier)) {
+ return ty;
+ }
+ }
+ return NULL;
+}
+
+static CLG_LogType *clg_ctx_type_register(CLogContext *ctx, const char *identifier)
+{
+ assert(clg_ctx_type_find_by_name(ctx, identifier) == NULL);
+ CLG_LogType *ty = MEM_callocN(sizeof(*ty), __func__);
+ ty->next = ctx->types;
+ ctx->types = ty;
+ strncpy(ty->identifier, identifier, sizeof(ty->identifier) - 1);
+ ty->ctx = ctx;
+ ty->level = ctx->default_type.level;
+
+ if (clg_ctx_filter_check(ctx, ty->identifier)) {
+ ty->flag |= CLG_FLAG_USE;
+ }
+ return ty;
+}
+
+static void clg_ctx_fatal_action(CLogContext *ctx, FILE *file_handle)
+{
+ if (ctx->callbacks.fatal_fn != NULL) {
+ ctx->callbacks.fatal_fn(file_handle);
+ }
+ fflush(file_handle);
+ abort();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Logging API
+ * \{ */
+
+static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool use_color)
+{
+ assert((unsigned int)severity < CLG_SEVERITY_LEN);
+ if (use_color) {
+ enum eCLogColor color = clg_severity_to_color(severity);
+ clg_str_append(cstr, clg_color_table[color]);
+ clg_str_append(cstr, clg_severity_as_text(severity));
+ clg_str_append(cstr, clg_color_table[COLOR_RESET]);
+ }
+ else {
+ clg_str_append(cstr, clg_severity_as_text(severity));
+ }
+}
+
+static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
+{
+ clg_str_append(cstr, " (");
+ clg_str_append(cstr, lg->identifier);
+ clg_str_append(cstr, "): ");
+}
+
+static void write_file_line_fn(CLogStringBuf *cstr, const char *file_line, const char *fn, const bool use_basename)
+{
+ uint file_line_len = strlen(file_line);
+ if (use_basename) {
+ uint file_line_offset = file_line_len;
+ while (file_line_offset-- > 0) {
+ if (file_line[file_line_offset] == PATHSEP_CHAR) {
+ file_line_offset++;
+ break;
+ }
+ }
+ file_line += file_line_offset;
+ file_line_len -= file_line_offset;
+ }
+ clg_str_append_with_len(cstr, file_line, file_line_len);
+
+
+ clg_str_append(cstr, " ");
+ clg_str_append(cstr, fn);
+ clg_str_append(cstr, ": ");
+}
+
+void CLG_log_str(
+ CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
+ const char *message)
+{
+ CLogStringBuf cstr;
+ char cstr_stack_buf[CLOG_BUF_LEN_INIT];
+ clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
+
+ write_severity(&cstr, severity, lg->ctx->use_color);
+ write_type(&cstr, lg);
+
+ {
+ write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
+ clg_str_append(&cstr, message);
+ }
+ clg_str_append(&cstr, "\n");
+
+ /* could be optional */
+ fwrite(cstr.data, cstr.len, 1, lg->ctx->output);
+ fflush(lg->ctx->output);
+
+ clg_str_free(&cstr);
+
+ if (severity == CLG_SEVERITY_FATAL) {
+ clg_ctx_fatal_action(lg->ctx, lg->ctx->output);
+ }
+}
+
+void CLG_logf(
+ CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
+ const char *fmt, ...)
+{
+ CLogStringBuf cstr;
+ char cstr_stack_buf[CLOG_BUF_LEN_INIT];
+ clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
+
+ write_severity(&cstr, severity, lg->ctx->use_color);
+ write_type(&cstr, lg);
+
+ {
+ write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
+
+ va_list ap;
+ va_start(ap, fmt);
+ clg_str_vappendf(&cstr, fmt, ap);
+ va_end(ap);
+ }
+ clg_str_append(&cstr, "\n");
+
+ /* could be optional */
+ fwrite(cstr.data, cstr.len, 1, lg->ctx->output);
+ fflush(lg->ctx->output);
+
+ clg_str_free(&cstr);
+
+ if (severity == CLG_SEVERITY_FATAL) {
+ clg_ctx_fatal_action(lg->ctx, lg->ctx->output);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Logging Context API
+ * \{ */
+
+static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
+{
+ ctx->output = file_handle;
+#if defined(__unix__)
+ ctx->use_color = isatty(fileno(file_handle));
+#endif
+}
+
+static void CLG_ctx_output_use_basename_set(CLogContext *ctx, int value)
+{
+ ctx->use_basename = (bool)value;
+}
+
+/** Action on fatal severity. */
+static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void (*fatal_fn)(void *file_handle))
+{
+ ctx->callbacks.fatal_fn = fatal_fn;
+}
+
+static void clg_ctx_type_filter_append(CLG_IDFilter **flt_list, const char *type_match, int type_match_len)
+{
+ if (type_match_len == 0) {
+ return;
+ }
+ CLG_IDFilter *flt = MEM_callocN(sizeof(*flt) + (type_match_len + 1), __func__);
+ flt->next = *flt_list;
+ *flt_list = flt;
+ memcpy(flt->match, type_match, type_match_len);
+ /* no need to null terminate since we calloc'd */
+}
+
+static void CLG_ctx_type_filter_exclude(CLogContext *ctx, const char *type_match, int type_match_len)
+{
+ clg_ctx_type_filter_append(&ctx->filters[0], type_match, type_match_len);
+}
+
+static void CLG_ctx_type_filter_include(CLogContext *ctx, const char *type_match, int type_match_len)
+{
+ clg_ctx_type_filter_append(&ctx->filters[1], type_match, type_match_len);
+}
+
+static CLogContext *CLG_ctx_init(void)
+{
+ CLogContext *ctx = MEM_callocN(sizeof(*ctx), __func__);
+ ctx->use_color = true;
+ ctx->default_type.level = 1;
+ CLG_ctx_output_set(ctx, stdout);
+
+ return ctx;
+}
+
+static void CLG_ctx_free(CLogContext *ctx)
+{
+ while (ctx->types != NULL) {
+ CLG_LogType *item = ctx->types;
+ ctx->types = item->next;
+ MEM_freeN(item);
+ }
+
+ for (uint i = 0; i < 2; i++) {
+ while (ctx->filters[i] != NULL) {
+ CLG_IDFilter *item = ctx->filters[i];
+ ctx->filters[i] = item->next;
+ MEM_freeN(item);
+ }
+ }
+ MEM_freeN(ctx);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Logging API
+ *
+ * Currently uses global context.
+ * \{ */
+
+/* We could support multiple at once, for now this seems not needed. */
+struct CLogContext *g_ctx = NULL;
+
+void CLG_init(void)
+{
+ g_ctx = CLG_ctx_init();
+
+ clg_color_table_init(g_ctx->use_color);
+}
+
+void CLG_exit(void)
+{
+ CLG_ctx_free(g_ctx);
+}
+
+void CLG_output_set(void *file_handle)
+{
+ CLG_ctx_output_set(g_ctx, file_handle);
+}
+
+void CLG_output_use_basename_set(int value)
+{
+ CLG_ctx_output_use_basename_set(g_ctx, value);
+}
+
+
+void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle))
+{
+ CLG_ctx_fatal_fn_set(g_ctx, fatal_fn);
+}
+
+void CLG_type_filter_exclude(const char *type_match, int type_match_len)
+{
+ CLG_ctx_type_filter_exclude(g_ctx, type_match, type_match_len);
+}
+
+void CLG_type_filter_include(const char *type_match, int type_match_len)
+{
+ CLG_ctx_type_filter_include(g_ctx, type_match, type_match_len);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Logging Reference API
+ * Use to avoid lookups each time.
+ * \{ */
+
+void CLG_logref_init(CLG_LogRef *clg_ref)
+{
+ assert(clg_ref->type == NULL);
+ CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier);
+ clg_ref->type = clg_ty ? clg_ty : clg_ctx_type_register(g_ctx, clg_ref->identifier);
+}
+
+/** \} */
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index df600feb1fe..b94c6e35823 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -810,7 +810,7 @@ int BLF_height_max(int fontid)
FontBLF *font = blf_get(fontid);
if (font && font->glyph_cache) {
- return font->glyph_cache->max_glyph_height;
+ return font->glyph_cache->glyph_height_max;
}
return 0;
@@ -821,7 +821,7 @@ float BLF_width_max(int fontid)
FontBLF *font = blf_get(fontid);
if (font && font->glyph_cache) {
- return font->glyph_cache->max_glyph_width;
+ return font->glyph_cache->glyph_width_max;
}
return 0.0f;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index b4ee0173010..07e568dd279 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -924,7 +924,7 @@ static void blf_font_wrap_apply(
wrap.start = wrap.last[0];
i = wrap.last[1];
pen_x = 0;
- pen_y -= font->glyph_cache->max_glyph_height;
+ pen_y -= font->glyph_cache->glyph_height_max;
g_prev = NULL;
lines += 1;
continue;
@@ -1138,7 +1138,7 @@ static void blf_font_fill(FontBLF *font)
#if BLF_BLUR_ENABLE
font->blur = 0;
#endif
- font->max_tex_size = -1;
+ font->tex_size_max = -1;
font->buf_info.fbuf = NULL;
font->buf_info.cbuf = NULL;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index f5a645af5e0..6183b54ebcc 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -148,34 +148,34 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
memset(gc->bucket, 0, sizeof(gc->bucket));
gc->textures = (GLuint *)MEM_mallocN(sizeof(GLuint) * 256, __func__);
- gc->ntex = 256;
- gc->cur_tex = BLF_CURTEX_UNSET;
- gc->x_offs = 0;
- gc->y_offs = 0;
+ gc->textures_len = 256;
+ gc->texture_current = BLF_TEXTURE_UNSET;
+ gc->offset_x = 0;
+ gc->offset_y = 0;
gc->pad = 3;
- gc->num_glyphs = (int)font->face->num_glyphs;
- gc->rem_glyphs = (int)font->face->num_glyphs;
+ gc->glyphs_len_max = (int)font->face->num_glyphs;
+ gc->glyphs_len_free = (int)font->face->num_glyphs;
gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f;
gc->descender = ((float)font->face->size->metrics.descender) / 64.0f;
if (FT_IS_SCALABLE(font->face)) {
- gc->max_glyph_width = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) *
+ gc->glyph_width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) *
(((float)font->face->size->metrics.x_ppem) /
((float)font->face->units_per_EM)));
- gc->max_glyph_height = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) *
+ gc->glyph_height_max = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) *
(((float)font->face->size->metrics.y_ppem) /
((float)font->face->units_per_EM)));
}
else {
- gc->max_glyph_width = (int)(((float)font->face->size->metrics.max_advance) / 64.0f);
- gc->max_glyph_height = (int)(((float)font->face->size->metrics.height) / 64.0f);
+ gc->glyph_width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f);
+ gc->glyph_height_max = (int)(((float)font->face->size->metrics.height) / 64.0f);
}
/* can happen with size 1 fonts */
- CLAMP_MIN(gc->max_glyph_width, 1);
- CLAMP_MIN(gc->max_glyph_height, 1);
+ CLAMP_MIN(gc->glyph_width_max, 1);
+ CLAMP_MIN(gc->glyph_height_max, 1);
gc->p2_width = 0;
gc->p2_height = 0;
@@ -205,9 +205,10 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
}
}
- if (gc->cur_tex != BLF_CURTEX_UNSET)
- glDeleteTextures((int)gc->cur_tex + 1, gc->textures);
- MEM_freeN((void *)gc->textures);
+ if (gc->texture_current != BLF_TEXTURE_UNSET) {
+ glDeleteTextures((int)gc->texture_current + 1, gc->textures);
+ }
+ MEM_freeN(gc->textures);
MEM_freeN(gc);
}
@@ -216,25 +217,27 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
int i;
/* move the index. */
- gc->cur_tex++;
+ gc->texture_current++;
- if (UNLIKELY(gc->cur_tex >= gc->ntex)) {
- gc->ntex *= 2;
- gc->textures = (GLuint *)MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->ntex);
+ if (UNLIKELY(gc->texture_current >= gc->textures_len)) {
+ gc->textures_len *= 2;
+ gc->textures = MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->textures_len);
}
- gc->p2_width = (int)blf_next_p2((unsigned int)((gc->rem_glyphs * gc->max_glyph_width) + (gc->pad * 2)));
- if (gc->p2_width > font->max_tex_size)
- gc->p2_width = font->max_tex_size;
+ gc->p2_width = (int)blf_next_p2((unsigned int)((gc->glyphs_len_free * gc->glyph_width_max) + (gc->pad * 2)));
+ if (gc->p2_width > font->tex_size_max) {
+ gc->p2_width = font->tex_size_max;
+ }
- i = (int)((gc->p2_width - (gc->pad * 2)) / gc->max_glyph_width);
- gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->num_glyphs / i) + 1) * gc->max_glyph_height));
+ i = (int)((gc->p2_width - (gc->pad * 2)) / gc->glyph_width_max);
+ gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max));
- if (gc->p2_height > font->max_tex_size)
- gc->p2_height = font->max_tex_size;
+ if (gc->p2_height > font->tex_size_max) {
+ gc->p2_height = font->tex_size_max;
+ }
- glGenTextures(1, &gc->textures[gc->cur_tex]);
- glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->cur_tex]));
+ glGenTextures(1, &gc->textures[gc->texture_current]);
+ glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->texture_current]));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -323,8 +326,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add");
g->c = c;
g->idx = (FT_UInt)index;
- g->xoff = -1;
- g->yoff = -1;
+ g->offset_x = -1;
+ g->offset_y = -1;
bitmap = slot->bitmap;
g->width = (int)bitmap.width;
g->height = (int)bitmap.rows;
@@ -457,38 +460,38 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
if (g->build_tex == 0) {
GlyphCacheBLF *gc = font->glyph_cache;
- if (font->max_tex_size == -1)
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);
+ if (font->tex_size_max == -1)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->tex_size_max);
- if (gc->cur_tex == BLF_CURTEX_UNSET) {
+ if (gc->texture_current == BLF_TEXTURE_UNSET) {
blf_glyph_cache_texture(font, gc);
- gc->x_offs = gc->pad;
- gc->y_offs = 0;
+ gc->offset_x = gc->pad;
+ gc->offset_y = 0;
}
- if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) {
- gc->x_offs = gc->pad;
- gc->y_offs += gc->max_glyph_height;
+ if (gc->offset_x > (gc->p2_width - gc->glyph_width_max)) {
+ gc->offset_x = gc->pad;
+ gc->offset_y += gc->glyph_height_max;
- if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) {
- gc->y_offs = 0;
+ if (gc->offset_y > (gc->p2_height - gc->glyph_height_max)) {
+ gc->offset_y = 0;
blf_glyph_cache_texture(font, gc);
}
}
- g->tex = gc->textures[gc->cur_tex];
- g->xoff = gc->x_offs;
- g->yoff = gc->y_offs;
+ g->tex = gc->textures[gc->texture_current];
+ g->offset_x = gc->offset_x;
+ g->offset_y = gc->offset_y;
/* prevent glTexSubImage2D from failing if the character
* asks for pixels out of bounds, this tends only to happen
* with very small sizes (5px high or less) */
- if (UNLIKELY((g->xoff + g->width) > gc->p2_width)) {
- g->width -= (g->xoff + g->width) - gc->p2_width;
+ if (UNLIKELY((g->offset_x + g->width) > gc->p2_width)) {
+ g->width -= (g->offset_x + g->width) - gc->p2_width;
BLI_assert(g->width > 0);
}
- if (UNLIKELY((g->yoff + g->height) > gc->p2_height)) {
- g->height -= (g->yoff + g->height) - gc->p2_height;
+ if (UNLIKELY((g->offset_y + g->height) > gc->p2_height)) {
+ g->height -= (g->offset_y + g->height) - gc->p2_height;
BLI_assert(g->height > 0);
}
@@ -503,21 +506,21 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, g->tex);
- glTexSubImage2D(GL_TEXTURE_2D, 0, g->xoff, g->yoff, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
glPixelStorei(GL_UNPACK_LSB_FIRST, lsb_first);
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
- g->uv[0][0] = ((float)g->xoff) / ((float)gc->p2_width);
- g->uv[0][1] = ((float)g->yoff) / ((float)gc->p2_height);
- g->uv[1][0] = ((float)(g->xoff + g->width)) / ((float)gc->p2_width);
- g->uv[1][1] = ((float)(g->yoff + g->height)) / ((float)gc->p2_height);
+ g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
+ g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
+ g->uv[1][0] = ((float)(g->offset_x + g->width)) / ((float)gc->p2_width);
+ g->uv[1][1] = ((float)(g->offset_y + g->height)) / ((float)gc->p2_height);
/* update the x offset for the next glyph. */
- gc->x_offs += (int)BLI_rctf_size_x(&g->box) + gc->pad;
+ gc->offset_x += (int)BLI_rctf_size_x(&g->box) + gc->pad;
- gc->rem_glyphs--;
+ gc->glyphs_len_free--;
g->build_tex = 1;
}
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index a34541f62bf..af2dc8a66e9 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -80,33 +80,33 @@ typedef struct GlyphCacheBLF {
unsigned int *textures;
/* size of the array. */
- unsigned int ntex;
+ unsigned int textures_len;
/* and the last texture, aka. the current texture. */
- unsigned int cur_tex;
+ unsigned int texture_current;
/* like bftgl, we draw every glyph in a big texture, so this is the
* current position inside the texture.
*/
- int x_offs;
- int y_offs;
+ int offset_x;
+ int offset_y;
/* and the space from one to other. */
int pad;
/* and the bigger glyph in the font. */
- int max_glyph_width;
- int max_glyph_height;
+ int glyph_width_max;
+ int glyph_height_max;
/* next two integer power of two, to build the texture. */
int p2_width;
int p2_height;
/* number of glyphs in the font. */
- int num_glyphs;
+ int glyphs_len_max;
- /* number of glyphs that we load here. */
- int rem_glyphs;
+ /* number of glyphs not yet loaded (decreases every glyph loaded). */
+ int glyphs_len_free;
/* ascender and descender value. */
float ascender;
@@ -135,8 +135,8 @@ typedef struct GlyphBLF {
unsigned int tex;
/* position inside the texture where this glyph is store. */
- int xoff;
- int yoff;
+ int offset_x;
+ int offset_y;
/* Bitmap data, from freetype. Take care that this
* can be NULL.
@@ -159,7 +159,7 @@ typedef struct GlyphBLF {
float pos_y;
/* with value of zero mean that we need build the texture. */
- short build_tex;
+ char build_tex;
} GlyphBLF;
typedef struct FontBufInfoBLF {
@@ -240,7 +240,7 @@ typedef struct FontBLF {
unsigned int size;
/* max texture size. */
- int max_tex_size;
+ int tex_size_max;
/* cache current OpenGL texture to save calls into the API */
unsigned int tex_bind_state;
@@ -284,6 +284,6 @@ typedef struct DirBLF {
char *path;
} DirBLF;
-#define BLF_CURTEX_UNSET ((unsigned int)-1)
+#define BLF_TEXTURE_UNSET ((unsigned int)-1)
#endif /* __BLF_INTERNAL_TYPES_H__ */
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_global.h b/source/blender/blenkernel/BKE_global.h
index 9adc00a67e6..c1b437661c5 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -80,6 +80,13 @@ typedef struct Global {
* however this is now only used for runtime options */
int f;
+ struct {
+ /* Logging vars (different loggers may use). */
+ int level;
+ /* FILE handle or use stderr (we own this so close when done). */
+ void *file;
+ } log;
+
/* debug flag, G_DEBUG, G_DEBUG_PYTHON & friends, set python or command line args */
int debug;
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 79f56cf25ef..aac43768acf 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_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index e9be6d9f7ca..4a3dd72836a 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -230,7 +230,6 @@ typedef struct PTCacheEditPoint {
} PTCacheEditPoint;
typedef struct PTCacheUndo {
- struct PTCacheUndo *next, *prev;
struct PTCacheEditPoint *points;
/* particles stuff */
@@ -243,12 +242,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_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
new file mode 100644
index 00000000000..6072ecfae4a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -0,0 +1,187 @@
+/*
+ * ***** 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_MEMFILE;
+extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE;
+extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT;
+extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE;
+extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE;
+
+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. */
+void BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut);
+void 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_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 f36a9e99a64..6a1c3ea883c 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -49,6 +49,7 @@ set(INC
../../../intern/mikktspace
../../../intern/smoke/extern
../../../intern/atomic
+ ../../../intern/clog
../../../intern/libmv
../../../extern/curve_fit_nd
)
@@ -194,6 +195,7 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
+ intern/undo_system.c
intern/unit.c
intern/workspace.c
intern/world.c
@@ -309,6 +311,7 @@ set(SRC
BKE_text.h
BKE_texture.h
BKE_tracking.h
+ BKE_undo_system.h
BKE_unit.h
BKE_workspace.h
BKE_world.h
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 953fef067b4..0a8c97ff175 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -63,7 +63,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 bf065ef992c..8058dbef577 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -47,7 +47,6 @@
#include "BIK_api.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index e9a6d0fe5a5..236b965ec34 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -85,6 +85,10 @@ void BKE_blender_free(void)
BKE_main_free(G.main);
G.main = NULL;
+ if (G.log.file != NULL) {
+ fclose(G.log.file);
+ }
+
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
IMB_exit();
@@ -134,6 +138,8 @@ void BKE_blender_globals_init(void)
#else
G.f &= ~G_SCRIPT_AUTOEXEC;
#endif
+
+ G.log.level = 1;
}
void BKE_blender_globals_clear(void)
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index dbfe3dee300..98482bcc8b1 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -42,27 +42,18 @@
#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_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"
#include "DEG_depsgraph.h"
@@ -74,46 +65,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 */
@@ -128,51 +94,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) {
@@ -188,222 +112,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 aebec3dfeed..8f156e8f267 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 4431ce38c23..8c4bced1563 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -48,7 +48,6 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_object.h"
-#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index a4ed7a9d63f..d0d3317b477 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/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 931fc09d235..bf36c437d60 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 d92d0d9edbf..c41ad78977e 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -54,7 +54,6 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.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 e0608efece2..6ec2d223e84 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -840,6 +840,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);
}
@@ -859,6 +860,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);
}
@@ -1229,6 +1231,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 2fc4c81cb0b..dd1315fe3fa 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 3256c16e2f6..ba5a6a25048 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -51,7 +51,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.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 7d977463abf..61c136d2c4f 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -42,7 +42,6 @@
#include "DNA_mask_types.h"
#include "BKE_curve.h"
-#include "BKE_global.h"
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index b80eca0ed59..8bb35dae96c 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_collection.h"
#include "BKE_DerivedMesh.h"
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 6fec55200d6..9215d56eb30 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/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..ddcd16f998e
--- /dev/null
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -0,0 +1,795 @@
+/*
+ * ***** 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/util/undo_system.c
+ * \ingroup edutil
+ *
+ * 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_MEMFILE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = 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, "%p '%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);
+ }
+ }
+ return ok;
+}
+
+static void undosys_step_decode(bContext *C, UndoStep *us, int dir)
+{
+ CLOG_INFO(&LOG, 2, "%p '%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, "%p '%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
+ }
+}
+
+/** \} */
+
+void 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, "%p, '%s', type='%s'", us, name, us->type->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);
+ }
+}
+
+void 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;
+ }
+ 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, "%p, '%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, "%p, '%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;
+ }
+ }
+ 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;
+
+ map->pmap[len_src].ptr = id;
+ map->pmap[len_src].index = len_src;
+ map->len = len_dst;
+
+ qsort(map->pmap, map->len, sizeof(*map->pmap), BLI_sortutil_cmp_ptr);
+}
+
+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);
+ }
+ 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;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index a57fc1fe027..e87e84736c8 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_world_types.h"
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/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 0da15fe5bbc..7b31415ddcf 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -160,6 +160,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 2b2dbb8a53b..97d132a3e40 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6274,7 +6274,6 @@ static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
- sce->toolsettings->particle.view_layer = NULL;
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
@@ -6561,7 +6560,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
wm->defaultconf = NULL;
wm->addonconf = NULL;
wm->userconf = NULL;
-
+ wm->undo_stack = NULL;
+
wm->message_bus = NULL;
BLI_listbase_clear(&wm->jobs);
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/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/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 36e6ec4ba7f..217de06d99b 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -33,21 +33,32 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.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 +76,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)
+{
+ 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);
+ DEG_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)
{
- // XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+ 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/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 1787e559913..f0b3233e35b 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1232,7 +1232,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_undo.c b/source/blender/editors/curve/editcurve_undo.c
index f8f96eb3bc9..5775835e5ff 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -30,18 +30,30 @@
#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_undo_system.h"
+#include "DEG_depsgraph.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 +61,12 @@ typedef struct {
ListBase fcurves, drivers;
int actnu;
int flag;
+ 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)
{
- 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 +74,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 +100,149 @@ 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;
ED_curve_updateAnimPaths(cu);
}
-static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
+static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu)
{
- 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;
+}
+
+static void undocurve_free_data(UndoCurve *uc)
+{
+ BKE_nurbList_free(&uc->nubase);
+
+ BKE_curve_editNurb_keyIndex_free(&uc->undoIndex);
- return undoCurve;
+ free_fcurves(&uc->fcurves);
+ free_fcurves(&uc->drivers);
}
-static void free_undoCurve(void *ucv)
+static Object *editcurve_object_from_context(bContext *C)
{
- UndoCurve *undoCurve = ucv;
+ 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;
+}
- BKE_nurbList_free(&undoCurve->nubase);
+/** \} */
- BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
- free_fcurves(&undoCurve->fcurves);
- free_fcurves(&undoCurve->drivers);
+typedef struct CurveUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-editmode. */
+ UndoRefID_Object obedit_ref;
+ UndoCurve data;
+} CurveUndoStep;
- MEM_freeN(undoCurve);
+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->step.data_size = us->data.undo_size;
+ return true;
}
-/* and this is all the undo system needs to know */
-void undo_push_curve(bContext *C, const char *name)
+static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
- undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
+ /* 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);
+ DEG_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);
+}
+
+static void curve_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+{
+ 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..d4d48e93f43 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,17 @@
#include "BKE_context.h"
#include "BKE_font.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.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 +59,10 @@
# define ARRAY_CHUNK_SIZE 32
#endif
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoFont {
wchar_t *textbuf;
struct CharInfo *textbufinfo;
@@ -62,6 +75,8 @@ typedef struct UndoFont {
BArrayState *textbufinfo;
} store;
#endif
+
+ size_t undo_size;
} UndoFont;
@@ -202,23 +217,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 +245,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 +282,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 +306,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)
{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+ 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);
+ DEG_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)
+{
+ 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 38927cf91e1..533ab21dbb6 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..fca9a2c10f2 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"
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 22a3224e563..1eee774fd3e 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/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index a35380ca547..0b1fb57af94 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -52,6 +52,7 @@ struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
struct Main;
+struct UndoType;
typedef struct EditBone {
struct EditBone *next, *prev;
@@ -149,7 +150,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);
@@ -198,6 +199,9 @@ 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);
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 4e25284dfa3..b9723e3865e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -63,6 +63,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,
@@ -99,8 +100,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);
@@ -131,6 +130,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
const struct Depsgraph *depsgraph,
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 a116cf5e5d0..95adea7fbe2 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -207,6 +207,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 WorkSpace *workspace, 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);
bool ED_object_mode_generic_enter(
struct bContext *C,
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 ee60d1c8eef..b3e274a235a 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -39,13 +39,14 @@ struct rcti;
struct PTCacheEdit;
struct Scene;
struct ViewLayer;
+struct UndoType;
/* particle edit mode */
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
struct PTCacheEdit *PE_create_current(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
void PE_current_changed(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
@@ -64,14 +65,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, struct ViewLayer *view_layer, const char *str);
-void PE_undo_step(struct Scene *scene, struct ViewLayer *view_layer, int step);
-void PE_undo(struct Scene *scene, struct ViewLayer *view_layer);
-void PE_redo(struct Scene *scene, struct ViewLayer *view_layer);
-bool PE_undo_is_valid(struct Scene *scene, struct ViewLayer *view_layer);
-void PE_undo_number(struct Scene *scene, struct ViewLayer *view_layer, int nr);
-const char *PE_undo_get_name(struct Scene *scene, struct ViewLayer *view_layer, 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 a81d63d9f25..574523696f5 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -36,10 +36,16 @@ struct Object;
struct RegionView3D;
struct ViewContext;
struct rcti;
+struct UndoStep;
+struct UndoType;
+struct ListBase;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, 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..5517e50aef4 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -30,12 +30,13 @@
#ifndef __ED_TEXT_H__
#define __ED_TEXT_H__
-struct bContext;
struct SpaceText;
struct ARegion;
+struct UndoType;
-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);
+#endif /* __ED_TEXT_H__ */
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 60c4b3593aa..5a373cebac1 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -35,6 +35,9 @@ struct bContext;
struct SpaceLink;
struct wmOperator;
struct wmOperatorType;
+struct UndoStack;
+struct ScrArea;
+struct PackedFile;
/* ed_util.c */
@@ -70,16 +73,12 @@ void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg
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 *));
+/* undo_system_types.c */
+void ED_undosys_type_init(void);
+void ED_undosys_type_free(void);
-
-void undo_editmode_clear(void);
+/* memfile_undo.c */
+struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack);
/* ************** XXX OLD CRUFT WARNING ************* */
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/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index aa817928f92..58fa08e5aa9 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,40 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_undo_system.h"
+#include "DEG_depsgraph.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 +83,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 +105,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);
+ DEG_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/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index aee9785ea83..657c3eb2a40 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -36,7 +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"
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 44fbb570f27..57e3f898401 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3762,7 +3762,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 ab91f4b34c7..aeb343707da 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -29,16 +29,25 @@
#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_undo_system.h"
+#include "DEG_depsgraph.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 +69,9 @@
# include "BLI_task.h"
#endif
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
#ifdef USE_ARRAY_STORE
@@ -95,6 +107,8 @@ typedef struct UndoMesh {
BArrayState *mselect;
} store;
#endif /* USE_ARRAY_STORE */
+
+ size_t undo_size;
} UndoMesh;
@@ -474,23 +488,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 +544,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
@@ -615,9 +622,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
@@ -644,28 +650,103 @@ 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 bool mesh_undosys_poll(bContext *C)
{
- /* 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;
+ 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);
+ 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);
+ DEG_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);
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+ 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 312dc000a2b..393fa475a9b 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -43,7 +43,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index 974bfb237d3..cc461c0c365 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -29,19 +29,32 @@
#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_undo_system.h"
+#include "DEG_depsgraph.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 +71,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 +85,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 +102,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;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
-static void *get_data(bContext *C)
+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;
+}
+
+static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ 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;
}
-/* this is undo system for MetaBalls */
-void undo_push_mball(bContext *C, const char *name)
+static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
- undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
+ 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);
+ DEG_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_modes.c b/source/blender/editors/object/object_modes.c
index 33b9ea49ec0..25795e75fef 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -152,6 +152,48 @@ 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
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return;
+ }
+ if (workspace->object_mode == mode) {
+ /* pass */
+ }
+ else if (workspace->object_mode != OB_MODE_OBJECT) {
+ if (ob && (workspace->object_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, workspace->object_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 224790269e2..9deae22e4e1 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -101,21 +101,20 @@ int PE_poll(bContext *C)
if (!scene || !view_layer || !ob || !(workspace->object_mode & OB_MODE_PARTICLE_EDIT)) {
return 0;
}
- return (PE_get_current(scene, view_layer, ob) != NULL);
+ return (PE_get_current(scene, ob) != NULL);
}
int PE_hair_poll(bContext *C)
{
const WorkSpace *workspace = CTX_wm_workspace(C);
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
PTCacheEdit *edit;
if (!scene || !ob || !(workspace->object_mode & OB_MODE_PARTICLE_EDIT)) {
return 0;
}
- edit= PE_get_current(scene, view_layer, ob);
+ edit= PE_get_current(scene, ob);
return (edit && edit->psys);
}
@@ -136,8 +135,6 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
if (edit==0) return;
- PTCacheUndo_clear(edit);
-
if (edit->points) {
LOOP_POINTS {
if (point->keys)
@@ -201,7 +198,7 @@ static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *br
* note: this function runs on poll, therefor it can runs many times a second
* keep it fast! */
static PTCacheEdit *pe_get_current(
- const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, int create)
+ const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int create)
{
ParticleEditSettings *pset= PE_settings(scene);
PTCacheEdit *edit = NULL;
@@ -212,7 +209,6 @@ static PTCacheEdit *pe_get_current(
return NULL;
pset->scene = scene;
- pset->view_layer = view_layer;
pset->object = ob;
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
@@ -241,18 +237,18 @@ static PTCacheEdit *pe_get_current(
if (psys->part && psys->part->type == PART_HAIR) {
if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
if (create && !psys->pointcache->edit)
- PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
+ PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
edit = pid->cache->edit;
}
else {
if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
- PE_create_particle_edit(eval_ctx, scene, view_layer, ob, NULL, psys);
+ PE_create_particle_edit(eval_ctx, scene, ob, NULL, psys);
edit = psys->edit;
}
}
else {
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
- PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, psys);
+ PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, psys);
edit = pid->cache->edit;
}
@@ -263,7 +259,7 @@ static PTCacheEdit *pe_get_current(
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
// NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
+ PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
@@ -272,7 +268,7 @@ static PTCacheEdit *pe_get_current(
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
// NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
+ PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
@@ -287,14 +283,14 @@ static PTCacheEdit *pe_get_current(
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, ViewLayer *view_layer, Object *ob)
+PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, view_layer, ob, 0);
+ return pe_get_current(NULL, scene, ob, 0);
}
PTCacheEdit *PE_create_current(const EvaluationContext *eval_ctx, Scene *scene, Object *ob)
{
- return pe_get_current(eval_ctx, scene, eval_ctx->view_layer, ob, 1);
+ return pe_get_current(eval_ctx, scene, ob, 1);
}
void PE_current_changed(const EvaluationContext *eval_ctx, Scene *scene, Object *ob)
@@ -385,7 +381,7 @@ static void PE_set_data(bContext *C, PEData *data)
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
CTX_data_eval_ctx(C, &data->eval_ctx);
- data->edit = PE_get_current(data->scene, data->view_layer, data->ob);
+ data->edit = PE_get_current(data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
@@ -1146,7 +1142,7 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
static void PE_update_selection(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, eval_ctx->view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
HairKey *hkey;
POINT_P; KEY_K;
@@ -1256,7 +1252,7 @@ void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, Object *o
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, eval_ctx->view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P;
if (!edit)
@@ -1396,7 +1392,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
POINT_P; KEY_K;
int action = RNA_enum_get(op->ptr, "action");
@@ -1448,9 +1444,8 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec
{
PEData data;
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
POINT_P; KEY_K;
if (!PE_start_edit(edit))
@@ -1642,7 +1637,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
data.select_action = SEL_SELECT;
scene = CTX_data_scene(C);
ob = CTX_data_active_object(C);
- edit = PE_get_current(scene, data.eval_ctx.view_layer, ob);
+ edit = PE_get_current(scene, ob);
rng = BLI_rng_new_srandom(seed);
@@ -1759,9 +1754,8 @@ void PE_deselect_all_visible(PTCacheEdit *edit)
int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
PEData data;
if (!PE_start_edit(edit))
@@ -1787,9 +1781,8 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
PEData data;
if (!PE_start_edit(edit))
@@ -1813,11 +1806,10 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
ARegion *ar= CTX_wm_region(C);
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
POINT_P; KEY_K;
@@ -1906,7 +1898,7 @@ static int hide_exec(bContext *C, wmOperator *op)
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
- PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
POINT_P; KEY_K;
@@ -1961,7 +1953,7 @@ static int reveal_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
- PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P; KEY_K;
@@ -2228,9 +2220,9 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
}
-static void rekey_particle_to_time(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int pa_index, float path_time)
+static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2570,9 +2562,8 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd;
KDTree *tree;
@@ -2663,10 +2654,9 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
ParticleEditSettings *pset= PE_settings(scene);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -2824,11 +2814,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
static void PE_mirror_x(
- Scene *scene, ViewLayer *view_layer, Object *ob, int tagged)
+ Scene *scene, Object *ob, int tagged)
{
Mesh *me= (Mesh *)(ob->data);
ParticleSystemModifierData *psmd;
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -2975,11 +2965,10 @@ static void PE_mirror_x(
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
- PE_mirror_x(scene, view_layer, ob, 0);
+ PE_mirror_x(scene, ob, 0);
update_world_cos(ob, edit);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
@@ -3116,7 +3105,7 @@ static void brush_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -3771,7 +3760,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob= CTX_data_active_object(C);
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
ARegion *ar= CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -3805,7 +3794,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
BrushEdit *bedit= op->customdata;
Scene *scene= bedit->scene;
- ViewLayer *view_layer = bedit->view_layer;
Object *ob= bedit->ob;
PTCacheEdit *edit= bedit->edit;
ParticleEditSettings *pset= PE_settings(scene);
@@ -4000,7 +3988,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
- PE_mirror_x(scene, view_layer, ob, 1);
+ PE_mirror_x(scene, ob, 1);
update_world_cos(ob, edit);
psys_free_path_cache(NULL, edit);
@@ -4223,7 +4211,7 @@ static void shape_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -4232,10 +4220,9 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -4310,7 +4297,7 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
Object *ob= OBACT(view_layer);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd = NULL;
POINT_P; KEY_K;
@@ -4348,7 +4335,7 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
/* initialize needed data for bake edit */
void PE_create_particle_edit(
- const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PointCache *cache, ParticleSystem *psys)
+ const EvaluationContext *eval_ctx, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
@@ -4450,9 +4437,6 @@ void PE_create_particle_edit(
if (psys && !cache)
recalc_emitter_field(ob, psys);
PE_update_object(eval_ctx, scene, ob, 1);
-
- PTCacheUndo_clear(edit);
- PE_undo_push(scene, view_layer, "Original");
}
}
@@ -4666,7 +4650,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
- PTCacheEdit *edit = PE_get_current(scene, eval_ctx.view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 45eb5923e57..1264800afc8 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -38,6 +38,7 @@
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -46,40 +47,31 @@
#include "BKE_global.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "DEG_depsgraph.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;
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
- 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);
-
- 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) {
@@ -87,8 +79,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;
}
@@ -99,8 +92,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]);
+ }
}
}
@@ -111,9 +105,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;
@@ -121,16 +119,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;
@@ -172,9 +174,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 {
@@ -192,150 +194,110 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
}
}
-void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
+static void undoptcache_free_data(PTCacheUndo *undo)
{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- 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, ViewLayer *view_layer, int step)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+/** \} */
- if (!edit) return;
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
- if (step==0) {
- get_PTCacheUndo(edit, edit->curundo);
- }
- else if (step==1) {
+typedef struct ParticleUndoStep {
+ UndoStep step;
+ UndoRefID_Scene scene_ref;
+ UndoRefID_Object object_ref;
+ PTCacheUndo data;
+} ParticleUndoStep;
- 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);
- }
- }
-
- DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
+static bool particle_undosys_poll(struct bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+
+ return (edit != NULL);
}
-bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
+static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-
- if (edit) {
- return (edit->undo.last != edit->undo.first);
- }
- return 0;
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ us->scene_ref.ptr = CTX_data_scene(C);
+ us->object_ref.ptr = OBACT(view_layer);
+ 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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ BLI_assert(0);
}
- BLI_freelistN(&edit->undo);
- edit->curundo= NULL;
}
-void PE_undo(Scene *scene, ViewLayer *view_layer)
+static void particle_undosys_step_free(UndoStep *us_p)
{
- PE_undo_step(scene, view_layer, 1);
+ ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ undoptcache_free_data(&us->data);
}
-void PE_redo(Scene *scene, ViewLayer *view_layer)
+static void particle_undosys_foreach_ID_ref(
+ UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
- PE_undo_step(scene, view_layer, -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, ViewLayer *view_layer, int nr)
+/* Export for ED_undo_sys. */
+void ED_particle_undosys_type(UndoType *ut)
{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- 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, view_layer, 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;
-/* 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, ViewLayer *view_layer, int nr, bool *r_active)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- PTCacheUndo *undo;
+ ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
- if (r_active) *r_active = false;
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = true;
- 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->step_size = sizeof(ParticleUndoStep);
}
+
+/** \} */
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 71810d09135..f6ece9d4bdc 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -931,10 +931,7 @@ static void copy_particle_edit(
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 {
@@ -963,9 +960,6 @@ static void copy_particle_edit(
recalc_lengths(edit);
recalc_emitter_field(ob, psys);
PE_update_object(eval_ctx, scene, ob, true);
-
- PTCacheUndo_clear(edit);
- PE_undo_push(scene, view_layer, "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 d9a7d288f9c..bb29a619139 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -48,7 +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"
@@ -69,6 +68,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 8888589b5d7..246bf79360f 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -70,9 +70,8 @@ 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(
- const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ViewLayer *view_layer,
+ const struct EvaluationContext *eval_ctx, 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 f77e164ba16..3bcc047bf5b 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -38,7 +38,6 @@
#include "DNA_scene_types.h"
#include "BKE_context.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 3b667520550..3553ffa5033 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -43,7 +43,6 @@
#include "BLT_translation.h"
#include "BKE_context.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 33ca6ea7495..f128a15ca6f 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 "BKE_workspace.h"
#include "DEG_depsgraph.h"
@@ -92,6 +93,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "BLO_undofile.h"
#include "render_intern.h"
@@ -901,7 +903,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/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 040bcc10ca2..80c58e5b91d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -52,7 +52,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 fb8dea2af0e..710ee7fcb44 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -43,6 +43,7 @@
#include "DEG_depsgraph.h"
#include "ED_view3d.h"
+#include "ED_paint.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -207,7 +208,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;
@@ -245,6 +246,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);
}
@@ -306,7 +309,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
@@ -346,6 +349,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;
@@ -383,7 +388,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;
@@ -448,10 +453,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;
@@ -566,9 +575,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;
@@ -591,6 +597,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..d5b7496fa3e 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -30,9 +30,13 @@
#include "DNA_space_types.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "ED_paint.h"
@@ -41,89 +45,125 @@
#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)
+{
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE);
}
+
+void ED_paintcurve_undo_push_end(void)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index b7cbdfecfe8..e72dac3b19e 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -57,6 +57,8 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
#include "DEG_depsgraph.h"
@@ -146,9 +148,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;
@@ -511,7 +515,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) {
@@ -1208,14 +1213,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);
DEG_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 2ce7c51b6b4..83a5a0d0b1b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1036,6 +1036,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 */
@@ -1044,9 +1046,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 58c03330256..6530fb5c750 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1501,15 +1501,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 d080c324d6c..5308ef0fae8 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -29,6 +29,11 @@
#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 "DNA_workspace_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -36,6 +41,8 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
@@ -45,10 +52,14 @@
#include "paint_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ char idname[MAX_ID_NAME]; /* name instead of pointer */
char ibufname[IMB_FILENAME_SIZE];
union {
@@ -65,6 +76,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,
@@ -130,13 +143,14 @@ 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)) {
@@ -162,10 +176,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;
@@ -175,7 +189,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;
}
@@ -215,8 +229,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);
@@ -226,10 +239,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;
@@ -347,50 +360,146 @@ 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);
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
}
void ED_image_undo_push_end(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, 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;
+} ImageUndoStep;
+
+static bool image_undosys_poll(bContext *C)
+{
+ const WorkSpace *workspace = CTX_wm_workspace(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 && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (obact && (workspace->object_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);
+ return true;
+}
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+static void image_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_restore_list(C, &us->tiles);
}
-static void image_undo_invalidate(void)
+static void image_undosys_step_free(UndoStep *us_p)
{
- UndoImageTile *tile;
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_free_list(&us->tiles);
+}
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
+/* 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->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)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(wm->undo_stack, 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 ccca0d248a5..e22b996c6e5 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);
@@ -303,10 +309,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_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 54cdbb18693..ba39d51700d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -125,6 +125,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 55950a51fba..7158c0fc88f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -48,6 +48,9 @@
#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 "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -57,6 +60,9 @@
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -64,12 +70,21 @@
#include "GPU_buffers.h"
#include "ED_paint.h"
+#include "ED_object.h"
+#include "ED_sculpt.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)
{
@@ -457,7 +472,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;
@@ -580,7 +595,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;
@@ -623,6 +638,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);
@@ -639,16 +656,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,
@@ -674,10 +692,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;
@@ -702,23 +721,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:
@@ -727,7 +746,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
break;
}
- BLI_addtail(lb, unode);
+ BLI_addtail(&usculpt->nodes, unode);
if (maxgrid) {
/* multires */
@@ -804,12 +823,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));
@@ -848,7 +868,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) {
@@ -889,8 +909,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;
@@ -960,17 +981,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);
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, 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;
@@ -980,7 +1002,98 @@ void sculpt_undo_push_end(void)
BKE_pbvh_node_layer_disp_free(unode->node);
}
- ED_undo_paint_push_end(UNDO_PAINT_MESH);
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, 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)) {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (workspace->object_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)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(wm->undo_stack, 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 80ec9107984..82768bedc95 100644
--- a/source/blender/editors/space_action/action_buttons.c
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -50,7 +50,6 @@
#include "BKE_curve.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..ca8dbbce1a1 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -54,7 +54,6 @@
#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"
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index 49cfc4b71b0..583beef5001 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_layer.h"
#include "BKE_object.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 9f689f35b10..233d83b76bf 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -2667,8 +2667,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_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 6bbec6a1a48..93e9b77a837 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -51,7 +51,6 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_layer.h"
#include "BKE_library.h"
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_ops.c b/source/blender/editors/space_text/text_ops.c
index 08b98ba51e0..4ea2d363250 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -756,7 +756,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)");
}
@@ -785,10 +788,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 *********************/
@@ -860,6 +866,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 *********************/
@@ -895,6 +904,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 *********************/
@@ -926,6 +938,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 *********************/
@@ -970,10 +985,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 *********************/
@@ -1003,10 +1021,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 *********************/
@@ -1041,6 +1062,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 +1198,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");
}
@@ -1295,6 +1322,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", "");
}
@@ -2919,6 +2949,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);
@@ -3024,6 +3057,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 +3117,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 +3240,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..4f62c409d58
--- /dev/null
+++ b/source/blender/editors/space_text/text_undo.c
@@ -0,0 +1,169 @@
+/*
+ * ***** 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_main.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 "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 TextUndoBuf {
+ char *buf;
+ int len;
+ int pos;
+} TextUndoBuf;
+
+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 bool text_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+{
+ TextUndoStep *us = (TextUndoStep *)us_p;
+ Text *text = CTX_data_edit_text(C);
+ us->text_ref.ptr = text;
+
+ BLI_assert(BLI_array_is_zeroed(&us->data, 1));
+
+ us->data.buf = text->undo_buf;
+ us->data.pos = text->undo_pos;
+ us->data.len = text->undo_len;
+
+ text->undo_buf = NULL;
+ text->undo_len = 0;
+ text->undo_pos = -1;
+
+ us->step.data_size = text->undo_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;
+
+ /* TODO(campbell): undo_system: move undo out of Text data block. */
+ text->undo_buf = us->data.buf;
+ text->undo_len = us->data.len;
+ if (dir < 0) {
+ text->undo_pos = us->data.pos;
+ txt_do_undo(text);
+ }
+ else {
+ text->undo_pos = -1;
+ txt_do_redo(text);
+ }
+ text->undo_buf = NULL;
+ text->undo_len = 0;
+ text->undo_pos = -1;
+
+ 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 = 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 = true;
+
+ ut->step_size = sizeof(TextUndoStep);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 5d267767cf9..3ccf65a8a69 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -1893,7 +1893,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
TransDataExtension *tx;
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, t->view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(t->scene, ob);
ParticleSystem *psys = NULL;
ParticleSystemModifierData *psmd = NULL;
PTCacheEditPoint *point;
@@ -2010,7 +2010,7 @@ void flushTransParticles(TransInfo *t)
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = NULL;
PTCacheEditPoint *point;
@@ -6550,7 +6550,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if ((t->view_layer->basact) &&
(ob = t->view_layer->basact->object) &&
(t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, t->view_layer, ob))
+ PE_get_current(t->scene, ob))
{
/* do nothing */
}
@@ -8307,7 +8307,7 @@ void createTransData(bContext *C, TransInfo *t)
}
}
else if (ob && (t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
- PE_start_edit(PE_get_current(scene, view_layer, ob)))
+ PE_start_edit(PE_get_current(scene, ob)))
{
createTransParticleVerts(C, t);
t->flag |= T_POINTS;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index fbe9c2ef240..e051b401f87 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -902,7 +902,7 @@ static void recalcData_objects(TransInfo *t)
BKE_pose_where_is(&t->eval_ctx, t->scene, ob);
}
else if (base && (t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, t->view_layer, base->object))
+ PE_get_current(t->scene, base->object))
{
if (t->state != TRANS_CANCEL) {
applyProject(t);
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 1839583015c..cb5b17b415e 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -976,7 +976,7 @@ static int calc_manipulator_stats(
/* pass */
}
else if (ob && workspace->object_mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 71a3322cb50..bd9077a2fca 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/clog
../../../../intern/glew-mx
)
@@ -41,9 +42,10 @@ set(INC_SYS
set(SRC
ed_transverts.c
ed_util.c
- editmode_undo.c
+ memfile_undo.c
numinput.c
undo.c
+ undo_system_types.c
util_intern.h
# general includes
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 7a5b8bfbda1..4bec0d9f114 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -62,6 +62,7 @@
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BKE_layer.h"
+#include "BKE_undo_system.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -93,13 +94,16 @@ void ED_editors_init(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ 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;
SWAP(int, reports->flag, reports_flag_prev);
-
/* toggle on modes for objects that were saved with these enabled. for
* e.g. linked objects we have to ensure that they are actually the
* active object in this scene. */
@@ -150,10 +154,16 @@ void ED_editors_exit(bContext *C)
if (!bmain)
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 (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->type == OB_MESH) {
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
deleted file mode 100644
index 43d1bfe1e6c..00000000000
--- a/source/blender/editors/util/editmode_undo.c
+++ /dev/null
@@ -1,373 +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_global.h"
-
-#include "DEG_depsgraph.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);
- }
-
- DEG_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/editors/util/memfile_undo.c b/source/blender/editors/util/memfile_undo.c
new file mode 100644
index 00000000000..95af0c48147
--- /dev/null
+++ b/source/blender/editors/util/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/util/memfile_undo.c
+ * \ingroup edutil
+ *
+ * Wrapper between 'BKE_undo.h' and 'BKE_undo_system.h'
+ */
+
+#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_util.h"
+#include "ED_render.h"
+
+
+#include "../blenloader/BLO_undofile.h"
+
+#include "util_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/undo.c b/source/blender/editors/util/undo.c
index b7101e7ae99..99e90eb73e8 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -48,6 +48,7 @@
#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
@@ -80,42 +81,27 @@
void ED_undo_push(bContext *C, const char *str)
{
- const WorkSpace *workspace = CTX_wm_workspace(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *obact = CTX_data_active_object(C);
-
- if (G.debug & G_DEBUG)
+ if (G.debug & G_DEBUG) {
printf("%s: %s\n", __func__, str);
-
- /* Always do it for now, this might need to be refined... */
- BKE_main_override_static_operations_create(CTX_data_main(C));
-
- 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 && workspace->object_mode & OB_MODE_PARTICLE_EDIT) {
- if (U.undosteps == 0) return;
+ const int steps = U.undosteps;
- PE_undo_push(CTX_data_scene(C), CTX_data_view_layer(C), str);
+ if (steps <= 0) {
+ return;
}
- else if (obact && workspace->object_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();
@@ -124,15 +110,10 @@ 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)
{
- const WorkSpace *workspace = CTX_wm_workspace(C);
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);
- ViewLayer *view_layer = CTX_data_view_layer(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 */
@@ -140,100 +121,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 && (workspace->object_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;
+ /* 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);
}
- }
-
- 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 {
+ BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
}
}
- 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 && workspace->object_mode & OB_MODE_TEXTURE_PAINT) {
- ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname);
- }
- else if (obact && workspace->object_mode & OB_MODE_SCULPT) {
- ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname);
- }
- else if (obact && workspace->object_mode & OB_MODE_PARTICLE_EDIT) {
- if (step == 1)
- PE_undo(scene, view_layer);
- else
- PE_redo(scene, view_layer);
- }
- 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);
- }
- }
-
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 */
@@ -274,48 +200,8 @@ 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)
{
- const WorkSpace *workspace = CTX_wm_workspace(C);
- 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 && (workspace->object_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 && workspace->object_mode & OB_MODE_TEXTURE_PAINT) {
- if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname))
- return 1;
- }
- else if (obact && workspace->object_mode & OB_MODE_SCULPT) {
- if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname))
- return 1;
- }
- else if (obact && workspace->object_mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_is_valid(CTX_data_scene(C), CTX_data_view_layer(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);
}
static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
@@ -493,112 +379,45 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev
/* ************************** */
-enum {
- UNDOSYSTEM_GLOBAL = 1,
- UNDOSYSTEM_EDITMODE = 2,
- UNDOSYSTEM_PARTICLE = 3,
- UNDOSYSTEM_IMAPAINT = 4,
- UNDOSYSTEM_SCULPT = 5,
-};
-
-static int get_undo_system(bContext *C)
-{
- const WorkSpace *workspace = CTX_wm_workspace(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 && (workspace->object_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 (workspace->object_mode & OB_MODE_PARTICLE_EDIT)
- return UNDOSYSTEM_PARTICLE;
- else if (workspace->object_mode & OB_MODE_TEXTURE_PAINT) {
- if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE))
- return UNDOSYSTEM_IMAPAINT;
- }
- else if (workspace->object_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;
-}
-
/* 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), CTX_data_view_layer(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;
+
+ 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;
/* XXX This won't work with non-default contexts (e.g. operators) :/ */
- item_tmp.name = IFACE_(name);
- if (active)
+ 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);
@@ -632,30 +451,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), CTX_data_view_layer(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;
diff --git a/source/blender/editors/util/undo_system_types.c b/source/blender/editors/util/undo_system_types.c
new file mode 100644
index 00000000000..a326d9eb859
--- /dev/null
+++ b/source/blender/editors/util/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/util/undo_system_types.c
+ * \ingroup edutil
+ */
+
+#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_util.h"
+#include "util_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_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/util_intern.h b/source/blender/editors/util/util_intern.h
index 0f650330951..6eda3900e91 100644
--- a/source/blender/editors/util/util_intern.h
+++ b/source/blender/editors/util/util_intern.h
@@ -34,13 +34,11 @@
/* 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;
+struct Main;
+struct Scene;
-#endif /* __UTIL_INTERN_H__ */
+/* memfile_undo.c */
+void ED_memfile_undosys_type(struct UndoType *ut);
+#endif /* __UTIL_INTERN_H__ */
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index a770b34ecc6..979b7d9b814 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -68,7 +68,6 @@
#include "MEM_guardedalloc.h"
-#include "BKE_global.h"
#ifdef WITH_AVI
# include "AVI_avi.h"
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index 00fb1a44dff..efcd7d1f35f 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -37,7 +37,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..2b6963b9170 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -43,7 +43,6 @@
#include "BLI_fileops.h"
#include "BLI_string.h"
-#include "BKE_global.h"
#include "imbuf.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index bc3fd46e1a9..d2810efca08 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1086,7 +1086,6 @@ typedef struct ParticleEditSettings {
int draw_step, fade_frames;
struct Scene *scene;
- struct ViewLayer *view_layer;
struct Object *object;
struct Object *shape_object;
} ParticleEditSettings;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index cc1db43758b..f03ff4ba8b7 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -59,6 +59,7 @@ struct ReportList;
struct Report;
struct uiLayout;
struct Stereo3dFormat;
+struct UndoStep;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
@@ -155,6 +156,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];
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 06c0260d08f..69237cad855 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -160,7 +160,7 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
if (!edit)
return;
@@ -181,8 +181,8 @@ static void rna_ParticleEdit_tool_set(PointerRNA *ptr, int value)
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
/* redraw hair completely if weight brush is/was used */
- if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->view_layer) {
- Object *ob = (pset->view_layer->basact) ? pset->view_layer->basact->object : NULL;
+ if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->object) {
+ Object *ob = pset->object;
if (ob) {
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
@@ -223,14 +223,14 @@ static int rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- return (pset->object && pset->scene && PE_get_current(pset->scene, pset->view_layer, pset->object));
+ return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
}
static int rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- PTCacheEdit *edit = PE_get_current(pset->scene, pset->view_layer, pset->object);
+ PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
return (edit && edit->psys);
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index cfd6d0c6db3..81c05433e66 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -38,7 +38,6 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_global.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
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 02021c44749..6af0e5b73ea 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"
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 81f52304b8f..7979751395a 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/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/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 234491a2186..da61a201ef6 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -43,6 +43,7 @@ set(INC
../nodes
../render/extern/include
../../gameengine/BlenderRoutines
+ ../../../intern/clog
../../../intern/ghost
../../../intern/guardedalloc
../../../intern/glew-mx
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index a09814cf5dd..4bd5bcfc056 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -731,6 +731,14 @@ typedef struct RecentFile {
char *filepath;
} RecentFile;
+/* Logging */
+struct CLG_LogRef;
+/* wm_init_exit.c */
+extern struct CLG_LogRef *WM_LOG_OPERATORS;
+extern struct CLG_LogRef *WM_LOG_HANDLERS;
+extern struct CLG_LogRef *WM_LOG_EVENTS;
+extern struct CLG_LogRef *WM_LOG_KEYMAPS;
+
#ifdef __cplusplus
}
diff --git a/source/blender/windowmanager/WM_undo.h b/source/blender/windowmanager/WM_undo.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/windowmanager/WM_undo.h
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 54c2d7a3aef..27107299863 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -63,6 +63,7 @@
#include "wm.h"
#include "ED_screen.h"
+#include "BKE_undo_system.h"
#ifdef WITH_PYTHON
#include "BPY_extern.h"
@@ -506,7 +507,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 630f858099f..4a4a993b386 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -43,6 +43,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "GHOST_C-api.h"
#include "BLI_blenlib.h"
@@ -608,14 +610,6 @@ int WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
}
-static void wm_operator_print(bContext *C, wmOperator *op)
-{
- /* context is needed for enum function */
- char *buf = WM_operator_pystring(C, op, false, true);
- puts(buf);
- MEM_freeN(buf);
-}
-
/**
* Sets the active region for this space from the context.
*
@@ -776,10 +770,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
}
if (retval & OPERATOR_FINISHED) {
- if (G.debug & G_DEBUG_WM) {
- /* todo - this print may double up, might want to check more flags then the FINISHED */
- wm_operator_print(C, op);
- }
+ CLOG_STR_INFO_N(WM_LOG_OPERATORS, 1, WM_operator_pystring(C, op, false, true));
if (caller_owns_reports == false) {
BKE_reports_print(op->reports, RPT_DEBUG); /* print out reports to console. */
@@ -1104,9 +1095,7 @@ bool WM_operator_last_properties_init(wmOperator *op)
IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
PropertyRNA *iterprop;
- if (G.debug & G_DEBUG_WM) {
- printf("%s: loading previous properties for '%s'\n", __func__, op->type->idname);
- }
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
iterprop = RNA_struct_iterator_property(op->type->srna);
@@ -1151,9 +1140,7 @@ bool WM_operator_last_properties_store(wmOperator *op)
}
if (op->properties) {
- if (G.debug & G_DEBUG_WM) {
- printf("%s: storing properties for '%s'\n", __func__, op->type->idname);
- }
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
op->type->last_properties = IDP_CopyProperty(op->properties);
return true;
}
@@ -1203,11 +1190,12 @@ static int wm_operator_invoke(
WM_operator_last_properties_init(op);
}
- if ((G.debug & G_DEBUG_HANDLERS) && ((event == NULL) || (event->type != MOUSEMOVE))) {
- printf("%s: handle evt %d region %p op %s\n",
- __func__, event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
+ if ((event == NULL) || (event->type != MOUSEMOVE)) {
+ CLOG_INFO(WM_LOG_HANDLERS, 2,
+ "handle evt %d win %p op %s",
+ event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
}
-
+
if (op->type->invoke && event) {
wm_region_mouse_co(C, event);
@@ -1232,9 +1220,9 @@ static int wm_operator_invoke(
}
else {
/* debug, important to leave a while, should never happen */
- printf("%s: invalid operator call '%s'\n", __func__, ot->idname);
+ CLOG_ERROR(WM_LOG_OPERATORS, "invalid operator call '%s'", op->idname);
}
-
+
/* Note, if the report is given as an argument then assume the caller will deal with displaying them
* currently python only uses this */
if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
@@ -1509,8 +1497,10 @@ int WM_operator_call_py(
if (is_undo && op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
wm->op_undo_depth--;
}
- else
- printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
+ else {
+ CLOG_WARN(WM_LOG_OPERATORS, "\"%s\" operator has no exec function, Python cannot call it", op->type->name);
+ }
+
#endif
/* not especially nice using undo depth here, its used so py never
@@ -1554,8 +1544,9 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wm
if (sa == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
- if (handler->op == NULL)
- printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
+ if (handler->op == NULL) {
+ CLOG_ERROR(WM_LOG_HANDLERS, "internal error: handler (%s) has invalid area", handler->op->type->idname);
+ }
}
else {
ARegion *ar;
@@ -1901,10 +1892,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
//retval &= ~OPERATOR_PASS_THROUGH;
}
}
-
}
else {
- printf("%s: error '%s' missing modal\n", __func__, op->idname);
+ CLOG_ERROR(WM_LOG_HANDLERS, "missing modal '%s'", op->idname);
}
}
else {
@@ -2195,19 +2185,15 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler */
-
- if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
- printf("%s: handled! '%s'\n", __func__, kmi->idname);
-
+ CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
break;
}
else {
if (action & WM_HANDLER_HANDLED) {
- if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
- printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
+ CLOG_INFO(WM_LOG_HANDLERS, 2, "handled - and pass on! '%s'", kmi->idname);
}
else {
- PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
+ CLOG_INFO(WM_LOG_HANDLERS, 2, "un-handled '%s'", kmi->idname);
}
}
}
@@ -2466,10 +2452,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
event->val = KM_CLICK;
- if (G.debug & (G_DEBUG_HANDLERS)) {
- printf("%s: handling CLICK\n", __func__);
- }
-
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
+
action |= wm_handlers_do_intern(C, event, handlers);
event->val = KM_RELEASE;
@@ -2708,8 +2692,8 @@ void wm_event_do_handlers(bContext *C)
/* take care of pie event filter */
if (wm_event_pie_filter(win, event)) {
- if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- printf("\n%s: event filtered due to pie button pressed\n", __func__);
+ if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed");
}
BLI_remlink(&win->queue, event);
wm_event_free(event);
@@ -3058,7 +3042,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap
wmEventHandler *handler;
if (!keymap) {
- printf("%s: called with NULL keymap\n", __func__);
+ CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap");
return NULL;
}
@@ -3679,8 +3663,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* double click test */
if (wm_event_is_double_click(&event, evt)) {
- if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
- printf("%s Send double click\n", __func__);
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
event.val = KM_DBL_CLICK;
}
if (event.val == KM_PRESS) {
@@ -3734,7 +3717,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* ghost should do this already for key up */
if (event.utf8_buf[0]) {
- printf("%s: ghost on your platform is misbehaving, utf8 events on key up!\n", __func__);
+ CLOG_ERROR(WM_LOG_EVENTS, "ghost on your platform is misbehaving, utf8 events on key up!");
}
event.utf8_buf[0] = '\0';
}
@@ -3747,8 +3730,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
if (event.utf8_buf[0]) {
if (BLI_str_utf8_size(event.utf8_buf) == -1) {
- printf("%s: ghost detected an invalid unicode character '%d'!\n",
- __func__, (int)(unsigned char)event.utf8_buf[0]);
+ CLOG_ERROR(WM_LOG_EVENTS,
+ "ghost detected an invalid unicode character '%d'",
+ (int)(unsigned char)event.utf8_buf[0]);
event.utf8_buf[0] = '\0';
}
}
@@ -3797,8 +3781,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* double click test */
/* if previous event was same type, and previous was release, and now it presses... */
if (wm_event_is_double_click(&event, evt)) {
- if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
- printf("%s Send double click\n", __func__);
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
evt->val = event.val = KM_DBL_CLICK;
}
@@ -3868,9 +3851,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
attach_ndof_data(&event, customdata);
wm_event_add(win, &event);
- if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
- printf("%s sending NDOF_MOTION, prev = %d %d\n", __func__, event.x, event.y);
-
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.x, event.y);
break;
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index e673b1d386b..bb9ff0ab8eb 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -87,10 +87,12 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "BKE_workspace.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"
@@ -534,9 +536,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));
}
}
@@ -1287,7 +1293,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 03bc1ae0a02..534b20ff22e 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -40,6 +40,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_genfile.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
@@ -53,6 +55,7 @@
#include "BLI_utildefines.h"
#include "BLO_writefile.h"
+#include "BLO_undofile.h"
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
@@ -132,6 +135,11 @@
# include "BKE_subsurf.h"
#endif
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_KEYMAPS, "wm.keymap");
+
static void wm_init_reports(bContext *C)
{
ReportList *reports = CTX_wm_reports(C);
@@ -147,11 +155,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 +175,7 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_manipulatortype_init();
wm_manipulatorgrouptype_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 */
@@ -482,7 +485,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;
@@ -493,7 +497,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);
}
@@ -516,11 +520,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();
@@ -608,8 +614,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
- BKE_undo_reset();
-
ED_file_exit(); /* for fsmenu */
UI_exit();
@@ -634,6 +638,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
* see also T50676. */
BKE_sound_exit();
+ CLG_exit();
+
BKE_blender_atexit();
if (MEM_get_memory_blocks_in_use() != 0) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index e86e80dddf6..0db67e0b199 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1,4 +1,5 @@
/*
+ *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -40,6 +41,7 @@
#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -902,11 +904,13 @@ wmKeyMapItem *WM_modalkeymap_find_propvalue(wmKeyMap *km, const int propvalue)
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
-
- if (ot)
+
+ if (ot) {
ot->modalkeymap = km;
- else
- printf("error: modalkeymap_assign, unknown operator %s\n", opname);
+ }
+ else {
+ CLOG_ERROR(WM_LOG_KEYMAPS, "unknown operator '%s'", opname);
+ }
}
static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 782d0c502a4..ebe68bc8f35 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -46,6 +46,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
@@ -142,12 +144,12 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
}
if (!quiet) {
- printf("search for unknown operator '%s', '%s'\n", idname_bl, idname);
+ CLOG_INFO(WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname);
}
}
else {
if (!quiet) {
- printf("search for empty operator\n");
+ CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator");
}
}
@@ -180,8 +182,7 @@ static wmOperatorType *wm_operatortype_append__begin(void)
static void wm_operatortype_append__end(wmOperatorType *ot)
{
if (ot->name == NULL) {
- fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
- ot->name = N_("Dummy Name");
+ CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
}
/* Allow calling _begin without _end in operatortype creation. */
@@ -269,7 +270,7 @@ static int wm_macro_exec(bContext *C, wmOperator *op)
}
}
else {
- printf("%s: '%s' cant exec macro\n", __func__, opm->type->idname);
+ CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
}
}
@@ -314,8 +315,9 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperator *opm = op->opm;
int retval = OPERATOR_FINISHED;
- if (opm == NULL)
- printf("%s: macro error, calling NULL modal()\n", __func__);
+ if (opm == NULL) {
+ CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()");
+ }
else {
retval = opm->type->modal(C, opm, event);
OPERATOR_RETVAL_CHECK(retval);
@@ -389,7 +391,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
const char *i18n_context;
if (WM_operatortype_find(idname, true)) {
- printf("%s: macro error: operator %s exists\n", __func__, idname);
+ CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname);
return NULL;
}
@@ -1198,11 +1200,14 @@ int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
uiLayout *layout;
if (prop == NULL) {
- printf("%s: %s has no enum property set\n", __func__, op->type->idname);
+ CLOG_ERROR(WM_LOG_OPERATORS,
+ "'%s' has no enum property set",
+ op->type->idname);
}
else if (RNA_property_type(prop) != PROP_ENUM) {
- printf("%s: %s \"%s\" is not an enum property\n",
- __func__, op->type->idname, RNA_property_identifier(prop));
+ CLOG_ERROR(WM_LOG_OPERATORS,
+ "'%s', '%s' is not an enum property",
+ op->type->idname, RNA_property_identifier(prop));
}
else if (RNA_property_is_set(op->ptr, prop)) {
const int retval = op->type->exec(C, op);
@@ -1956,8 +1961,9 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
}
else {
- printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
- x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
+ CLOG_ERROR(WM_LOG_OPERATORS,
+ "Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
}
IMB_freeImBuf(ibuf_template);
}
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 177e9744510..1adef28f2c8 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -26,6 +26,7 @@
setup_libdirs()
blender_include_dirs(
+ ../../intern/clog
../../intern/guardedalloc
../../intern/glew-mx
../blender/blenlib
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 78bab14cd96..2aa60c3e2a7 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -42,6 +42,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_genfile.h"
#include "BLI_args.h"
@@ -49,6 +51,7 @@
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "BLI_string.h"
+#include "BLI_system.h"
/* mostly init functions */
#include "BKE_appdir.h"
@@ -180,6 +183,11 @@ static void callback_main_atexit(void *user_data)
#endif
}
+static void callback_clg_fatal(void *fp)
+{
+ BLI_system_backtrace(fp);
+}
+
/** \} */
@@ -304,6 +312,10 @@ int main(
sdlewInit();
#endif
+ /* Initialize logging */
+ CLG_init();
+ CLG_fatal_fn_set(callback_clg_fatal);
+
C = CTX_create();
#ifdef WITH_PYTHON_MODULE
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index df4946a8175..3a478d0b9d4 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -30,6 +30,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#ifdef WIN32
# include "BLI_winstuff.h"
#endif
@@ -528,6 +530,12 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--python-exit-code");
BLI_argsPrintArgDoc(ba, "--addons");
+ printf("\n");
+ printf("Logging Options:\n");
+ BLI_argsPrintArgDoc(ba, "--log");
+ BLI_argsPrintArgDoc(ba, "--log-level");
+ BLI_argsPrintArgDoc(ba, "--log-show-basename");
+ BLI_argsPrintArgDoc(ba, "--log-file");
printf("\n");
printf("Debug Options:\n");
@@ -702,6 +710,109 @@ static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(
return 0;
}
+static const char arg_handle_log_level_set_doc[] =
+"<level>\n"
+"\n"
+"\tSet the logging verbosity level (higher for more details) defaults to 1."
+;
+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)) {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: '%s' no args given.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_log_show_basename_set_doc[] =
+"\n\tOnly show file name in output (not the leading path)."
+;
+static int arg_handle_log_show_basename_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ CLG_output_use_basename_set(true);
+ return 0;
+}
+
+static const char arg_handle_log_file_set_doc[] =
+"<filename>\n"
+"\n"
+"\tSet a file to output the log to."
+;
+static int arg_handle_log_file_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "--log-file";
+ if (argc > 1) {
+ errno = 0;
+ FILE *fp = BLI_fopen(argv[1], "w");
+ if (fp == NULL) {
+ const char *err_msg = errno ? strerror(errno) : "unknown";
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+ else {
+ if (UNLIKELY(G.log.file != NULL)) {
+ fclose(G.log.file);
+ }
+ G.log.file = fp;
+ CLG_output_set(G.log.file);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: '%s' no args given.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_log_set_doc[] =
+"<match>\n"
+"\tEnable logging categories, taking a single comma separated argument.\n"
+"\tMultiple categories can be matched using a '.*' suffix,\n"
+"\tso '--log \"wm.*\"' logs every kind of window-manager message.\n"
+"\tUse \"^\" prefix to ignore, so '--log \"*,^wm.operator.*\"' logs all except for 'wm.operators.*'\n"
+"\tUse \"*\" to log everything."
+;
+static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "--log";
+ if (argc > 1) {
+ const char *str_step = argv[1];
+ while (*str_step) {
+ const char *str_step_end = strchr(str_step, ',');
+ int str_step_len = str_step_end ? (str_step_end - str_step) : strlen(str_step);
+
+ if (str_step[0] == '^') {
+ CLG_type_filter_exclude(str_step + 1, str_step_len - 1);
+ }
+ else {
+ CLG_type_filter_include(str_step, str_step_len);
+ }
+
+ if (str_step_end) {
+ /* typically only be one, but don't fail on multiple.*/
+ while (*str_step_end == ',') {
+ str_step_end++;
+ }
+ str_step = str_step_end;
+ }
+ else {
+ break;
+ }
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: '%s' no args given.\n", arg_id);
+ return 0;
+ }
+}
+
static const char arg_handle_debug_mode_set_doc[] =
"\n"
"\tTurn debugging on.\n"
@@ -1657,7 +1768,7 @@ static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, vo
}
static const char arg_handle_python_exit_code_set_doc[] =
-"\n"
+"<code>\n"
"\tSet the exit-code in [0..255] to exit if a Python exception is raised\n"
"\t(only for scripts executed from the command line), zero disables."
;
@@ -1683,7 +1794,8 @@ static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UN
}
static const char arg_handle_addons_set_doc[] =
-"\n\tComma separated list of add-ons (no spaces)."
+"<addon(s)>\n"
+"\tComma separated list of add-ons (no spaces)."
;
static int arg_handle_addons_set(int argc, const char **argv, void *data)
{
@@ -1803,6 +1915,11 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--log", CB(arg_handle_log_set), ba);
+ BLI_argsAdd(ba, 1, NULL, "--log-level", CB(arg_handle_log_level_set), ba);
+ BLI_argsAdd(ba, 1, NULL, "--log-show-basename", CB(arg_handle_log_show_basename_set), ba);
+ BLI_argsAdd(ba, 1, NULL, "--log-file", CB(arg_handle_log_file_set), ba);
+
BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
#ifdef WITH_FFMPEG
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/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp
index 91e8e4fd42b..ae79284288d 100644
--- a/source/gameengine/Ketsji/KX_FontObject.cpp
+++ b/source/gameengine/Ketsji/KX_FontObject.cpp
@@ -142,7 +142,7 @@ int GetFontId(VFont *vfont)
fontid = BLF_load("default");
/* XXX the following code is supposed to work (after you add get_builtin_packedfile to BKE_font.h )
- * unfortunately it's crashing on blf_glyph.c:173 because gc->max_glyph_width is 0
+ * unfortunately it's crashing on blf_glyph.c:173 because gc->glyph_width_max is 0
*/
// packedfile=get_builtin_packedfile();
// fontid= BLF_load_mem(font->name, (unsigned char*)packedfile->data, packedfile->size);