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:
authorAntonio Vazquez <blendergit@gmail.com>2021-07-11 19:56:43 +0300
committerAntonio Vazquez <blendergit@gmail.com>2021-07-11 19:56:43 +0300
commitd947b012f7492b5f9bfe80ad9de8c57ad581d6d6 (patch)
tree6345d890acdd9176ab434102edca5d17264b672d
parent955d3a517a95fd9d87e9bdc0d2f50665caf4b1ec (diff)
parent2289e26fa306c3edc60a6b5b776646c6fd1c33dc (diff)
Merge branch 'master' into temp-gpencil-bezier-stroke-typetemp-gpencil-bezier-stroke-type
-rw-r--r--build_files/build_environment/cmake/versions.cmake4
-rwxr-xr-xbuild_files/build_environment/install_deps.sh8
-rw-r--r--build_files/windows/autodetect_msvc.cmd4
-rw-r--r--intern/cycles/render/session.cpp183
-rw-r--r--intern/cycles/render/session.h3
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp4
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py8
-rw-r--r--release/scripts/startup/bl_ui/space_node.py93
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py14
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/action.c38
-rw-r--r--source/blender/blenkernel/intern/action_test.cc144
-rw-r--r--source/blender/blenkernel/intern/anim_data.c32
-rw-r--r--source/blender/blenkernel/intern/ipo.c26
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenlib/BLI_array_utils.h31
-rw-r--r--source/blender/blenlib/BLI_enumerable_thread_specific.hh16
-rw-r--r--source/blender/blenlib/intern/array_utils.c82
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_array_utils_test.cc50
-rw-r--r--source/blender/blenloader/intern/versioning_300.c32
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c2
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc4
-rw-r--r--source/blender/draw/engines/image/image_engine.c39
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c15
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/object/object_relations.c33
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/node_buttons.c250
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc3
-rw-r--r--source/blender/editors/space_node/node_intern.h3
-rw-r--r--source/blender/editors/space_node/space_node.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c73
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c9
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c7
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc2
-rwxr-xr-xtests/python/modules/render_report.py2
52 files changed, 710 insertions, 558 deletions
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 2d015440d5d..bb0ee961f05 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -456,9 +456,9 @@ set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589)
set(NASM_HASH_TYPE SHA256)
set(NASM_FILE nasm-${NASM_VERSION}.tar.gz)
-set(XR_OPENXR_SDK_VERSION 1.0.14)
+set(XR_OPENXR_SDK_VERSION 1.0.17)
set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz)
-set(XR_OPENXR_SDK_HASH 0df6b2fd6045423451a77ff6bc3e1a75)
+set(XR_OPENXR_SDK_HASH bf0fd8828837edff01047474e90013e1)
set(XR_OPENXR_SDK_HASH_TYPE MD5)
set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 1b6b34435e1..c5b7198d012 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -572,7 +572,7 @@ FFMPEG_FORCE_REBUILD=false
FFMPEG_SKIP=false
_ffmpeg_list_sep=";"
-XR_OPENXR_VERSION="1.0.14"
+XR_OPENXR_VERSION="1.0.17"
XR_OPENXR_VERSION_SHORT="1.0"
XR_OPENXR_VERSION_MIN="1.0.8"
XR_OPENXR_VERSION_MAX="2.0"
@@ -1108,9 +1108,9 @@ FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
XR_OPENXR_USE_REPO=false
XR_OPENXR_SOURCE=("https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_VERSION}.tar.gz")
-#~ XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
-#~ XR_OPENXR_REPO_UID="5900c51562769b03bea699dc0352cae56acb6419d"
-#~ XR_OPENXR_REPO_BRANCH="master"
+XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
+XR_OPENXR_REPO_UID="bf21ccb1007bb531b45d9978919a56ea5059c245"
+XR_OPENXR_REPO_BRANCH="master"
# C++11 is required now
CXXFLAGS_BACK=$CXXFLAGS
diff --git a/build_files/windows/autodetect_msvc.cmd b/build_files/windows/autodetect_msvc.cmd
index 6cee4765b93..a4ab8929040 100644
--- a/build_files/windows/autodetect_msvc.cmd
+++ b/build_files/windows/autodetect_msvc.cmd
@@ -1,9 +1,9 @@
echo No explicit msvc version requested, autodetecting version.
-call "%~dp0\detect_msvc2017.cmd"
+call "%~dp0\detect_msvc2019.cmd"
if %ERRORLEVEL% EQU 0 goto DetectionComplete
-call "%~dp0\detect_msvc2019.cmd"
+call "%~dp0\detect_msvc2017.cmd"
if %ERRORLEVEL% EQU 0 goto DetectionComplete
call "%~dp0\detect_msvc2022.cmd"
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index ca90af77f6e..19d4a66353d 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -227,66 +227,25 @@ void Session::run_gpu()
progress.set_render_start_time();
while (!progress.get_cancel()) {
- /* advance to next tile */
- bool no_tiles = !tile_manager.next();
+ const bool no_tiles = !run_update_for_next_iteration();
- DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
- kernel_state = device->get_active_kernel_switch_state();
- }
-
- if (params.background) {
- /* if no work left and in background mode, we can stop immediately */
- if (no_tiles) {
+ if (params.background) {
+ /* if no work left and in background mode, we can stop immediately */
progress.set_status("Finished");
break;
}
}
- else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) {
- reset_gpu(tile_manager.params, params.samples);
+ if (run_wait_for_work(no_tiles)) {
+ continue;
}
- else {
- /* if in interactive mode, and we are either paused or done for now,
- * wait for pause condition notify to wake up again */
- thread_scoped_lock pause_lock(pause_mutex);
-
- if (!pause && !tile_manager.done()) {
- /* reset could have happened after no_tiles was set, before this lock.
- * in this case we shall not wait for pause condition
- */
- }
- else if (pause || no_tiles) {
- update_status_time(pause, no_tiles);
-
- while (1) {
- scoped_timer pause_timer;
- pause_cond.wait(pause_lock);
- if (pause) {
- progress.add_skip_time(pause_timer, params.background);
- }
-
- update_status_time(pause, no_tiles);
- progress.set_update();
-
- if (!pause)
- break;
- }
- }
-
- if (progress.get_cancel())
- break;
+ if (progress.get_cancel()) {
+ break;
}
if (!no_tiles) {
- /* update scene */
- scoped_timer update_timer;
- if (update_scene()) {
- profiler.reset(scene->shaders.size(), scene->objects.size());
- }
- progress.add_skip_time(update_timer, params.background);
-
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -729,82 +688,27 @@ void Session::run_cpu()
last_update_time = time_dt();
last_display_time = last_update_time;
- {
- /* reset once to start */
- thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers_mutex);
- thread_scoped_lock display_lock(display_mutex);
-
- reset_(delayed_reset.params, delayed_reset.samples);
- delayed_reset.do_reset = false;
- }
-
while (!progress.get_cancel()) {
- /* advance to next tile */
- bool no_tiles = !tile_manager.next();
+ const bool no_tiles = !run_update_for_next_iteration();
bool need_copy_to_display_buffer = false;
- DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
- kernel_state = device->get_active_kernel_switch_state();
- }
-
- if (params.background) {
- /* if no work left and in background mode, we can stop immediately */
- if (no_tiles) {
+ if (params.background) {
+ /* if no work left and in background mode, we can stop immediately */
progress.set_status("Finished");
break;
}
}
- else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) {
- reset_cpu(tile_manager.params, params.samples);
+ if (run_wait_for_work(no_tiles)) {
+ continue;
}
- else {
- /* if in interactive mode, and we are either paused or done for now,
- * wait for pause condition notify to wake up again */
- thread_scoped_lock pause_lock(pause_mutex);
-
- if (!pause && delayed_reset.do_reset) {
- /* reset once to start */
- thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers_mutex);
- thread_scoped_lock display_lock(display_mutex);
-
- reset_(delayed_reset.params, delayed_reset.samples);
- delayed_reset.do_reset = false;
- }
- else if (pause || no_tiles) {
- update_status_time(pause, no_tiles);
-
- while (1) {
- scoped_timer pause_timer;
- pause_cond.wait(pause_lock);
- if (pause) {
- progress.add_skip_time(pause_timer, params.background);
- }
-
- update_status_time(pause, no_tiles);
- progress.set_update();
-
- if (!pause)
- break;
- }
- }
-
- if (progress.get_cancel())
- break;
+ if (progress.get_cancel()) {
+ break;
}
if (!no_tiles) {
- /* update scene */
- scoped_timer update_timer;
- if (update_scene()) {
- profiler.reset(scene->shaders.size(), scene->objects.size());
- }
- progress.add_skip_time(update_timer, params.background);
-
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -894,6 +798,63 @@ void Session::run()
progress.set_update();
}
+bool Session::run_update_for_next_iteration()
+{
+ thread_scoped_lock scene_lock(scene->mutex);
+ thread_scoped_lock reset_lock(delayed_reset.mutex);
+
+ if (delayed_reset.do_reset) {
+ thread_scoped_lock buffers_lock(buffers_mutex);
+ reset_(delayed_reset.params, delayed_reset.samples);
+ delayed_reset.do_reset = false;
+ }
+
+ const bool have_tiles = tile_manager.next();
+
+ if (have_tiles) {
+ scoped_timer update_timer;
+ if (update_scene()) {
+ profiler.reset(scene->shaders.size(), scene->objects.size());
+ }
+ progress.add_skip_time(update_timer, params.background);
+ }
+
+ return have_tiles;
+}
+
+bool Session::run_wait_for_work(bool no_tiles)
+{
+ /* In an offline rendering there is no pause, and no tiles will mean the job is fully done. */
+ if (params.background) {
+ return false;
+ }
+
+ thread_scoped_lock pause_lock(pause_mutex);
+
+ if (!pause && !no_tiles) {
+ return false;
+ }
+
+ update_status_time(pause, no_tiles);
+
+ while (true) {
+ scoped_timer pause_timer;
+ pause_cond.wait(pause_lock);
+ if (pause) {
+ progress.add_skip_time(pause_timer, params.background);
+ }
+
+ update_status_time(pause, no_tiles);
+ progress.set_update();
+
+ if (!pause) {
+ break;
+ }
+ }
+
+ return no_tiles;
+}
+
bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params)
{
if (device_use_gl)
@@ -1012,8 +973,6 @@ void Session::wait()
bool Session::update_scene()
{
- thread_scoped_lock scene_lock(scene->mutex);
-
/* update camera if dimensions changed for progressive render. the camera
* knows nothing about progressive or cropped rendering, it just gets the
* image dimensions passed in */
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 43ff07e5884..bc3b8366c05 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -178,6 +178,9 @@ class Session {
void run();
+ bool run_update_for_next_iteration();
+ bool run_wait_for_work(bool no_tiles);
+
void update_status_time(bool show_pause = false, bool show_done = false);
void render(bool use_denoise);
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index aaac62a1a03..c1cb5f29e2e 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -365,8 +365,8 @@ void StereoProjection(float left,
* of zero parallax.
*
* -0.31
- * eye = half the eye separation; positive for the right eye subfield,
- * negative for the left eye subfield.
+ * eye = half the eye separation; positive for the right eye sub-field,
+ * negative for the left eye sub-field.
*/
{
float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw, dx, dy, n_over_d;
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 7c6a67d4960..b76afc6f35f 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5535,6 +5535,7 @@ def km_view3d_walk_modal(_params):
("DECELERATE", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "any": True, "repeat": True}, None),
("ACCELERATE", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "any": True}, None),
("DECELERATE", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "any": True}, None),
+ ("AXIS_LOCK_Z", {"type": 'Z', "value": 'PRESS'}, None),
])
return keymap
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 926be1ff820..afbc3abf302 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -72,8 +72,9 @@ class CLIP_PT_marker_display(Panel):
col.prop(view, "show_marker_pattern", text="Pattern")
col.prop(view, "show_marker_search", text="Search")
- col.active = view.show_track_path
col.prop(view, "show_track_path", text="Path")
+ col = col.column()
+ col.active = view.show_track_path
col.prop(view, "path_length", text="Length")
col = row.column()
@@ -113,7 +114,6 @@ class CLIP_PT_clip_display(Panel):
row = layout.row()
col = row.column()
col.prop(sc.clip_user, "use_render_undistorted", text="Render Undistorted")
- col.prop(sc, "lock_selection", text="Lock to Selection")
col = row.column()
col.prop(sc, "show_stable", text="Show Stable")
col.prop(sc, "show_grid", text="Grid")
@@ -190,7 +190,7 @@ class CLIP_HT_header(Header):
row.prop(sc, "pivot_point", text="", icon_only=True)
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
- row.prop(sc, "lock_selection", icon=icon, text="")
+ row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
elif sc.view == 'GRAPH':
@@ -250,7 +250,7 @@ class CLIP_HT_header(Header):
row.popover(panel='CLIP_PT_mask_display')
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
- row.prop(sc, "lock_selection", icon=icon, text="")
+ row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
def draw(self, context):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 1208ca0a64a..fba86676ad4 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -694,6 +694,97 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
layout.template_node_socket(color=color)
+class NodeTreeInterfacePanel:
+ def draw_socket_list(self, context, in_out, sockets_propname, active_socket_propname):
+ layout = self.layout
+
+ snode = context.space_data
+ tree = snode.edit_tree
+ sockets = getattr(tree, sockets_propname)
+ active_socket_index = getattr(tree, active_socket_propname)
+ active_socket = sockets[active_socket_index] if active_socket_index >= 0 else None
+
+ split = layout.row()
+
+ split.template_list("NODE_UL_interface_sockets", in_out, tree, sockets_propname, tree, active_socket_propname)
+
+ ops_col = split.column()
+
+ add_remove_col = ops_col.column(align=True)
+ props = add_remove_col.operator("node.tree_socket_add", icon='ADD', text="")
+ props.in_out = in_out
+ props = add_remove_col.operator("node.tree_socket_remove", icon='REMOVE', text="")
+ props.in_out = in_out
+
+ ops_col.separator()
+
+ up_down_col = ops_col.column(align=True)
+ props = up_down_col.operator("node.tree_socket_move", icon='TRIA_UP', text="")
+ props.in_out = in_out
+ props.direction = 'UP'
+ props = up_down_col.operator("node.tree_socket_move", icon='TRIA_DOWN', text="")
+ props.in_out = in_out
+ props.direction = 'DOWN'
+
+ if active_socket is not None:
+ # Mimicking property split.
+ layout.use_property_split = False
+ layout.use_property_decorate = False
+ layout_row = layout.row(align=True)
+ layout_split = layout_row.split(factor=0.4, align=True)
+
+ label_column = layout_split.column(align=True)
+ label_column.alignment = 'RIGHT'
+ # Menu to change the socket type.
+ label_column.label(text="Type")
+
+ property_row = layout_split.row(align=True)
+ props = property_row.operator_menu_enum(
+ "node.tree_socket_change_type",
+ "socket_type",
+ text=active_socket.bl_label if active_socket.bl_label else active_socket.bl_idname
+ )
+ props.in_out = in_out
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ layout.prop(active_socket, "name")
+ # Display descriptions only for Geometry Nodes, since it's only used in the modifier panel.
+ if tree.type == 'GEOMETRY':
+ layout.prop(active_socket, "description")
+ active_socket.draw(context, layout)
+
+
+class NODE_PT_node_tree_interface_inputs(NodeTreeInterfacePanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Group"
+ bl_label = "Inputs"
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode.edit_tree is not None
+
+ def draw(self, context):
+ self.draw_socket_list(context, "IN", "inputs", "active_input")
+
+class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Group"
+ bl_label = "Outputs"
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode.edit_tree is not None
+
+ def draw(self, context):
+ self.draw_socket_list(context, "OUT", "outputs", "active_output")
+
+
# Grease Pencil properties
class NODE_PT_annotation(AnnotationDataPanel, Panel):
bl_space_type = 'NODE_EDITOR'
@@ -752,6 +843,8 @@ classes = (
NODE_PT_quality,
NODE_PT_annotation,
NODE_UL_interface_sockets,
+ NODE_PT_node_tree_interface_inputs,
+ NODE_PT_node_tree_interface_outputs,
node_panel(EEVEE_MATERIAL_PT_settings),
node_panel(MATERIAL_PT_viewport),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 2cf0ad79b6a..98033cc2608 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2763,23 +2763,27 @@ class VIEW3D_MT_make_single_user(Menu):
props = layout.operator("object.make_single_user", text="Object")
props.object = True
- props.obdata = props.material = props.animation = False
+ props.obdata = props.material = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object & Data")
props.object = props.obdata = True
- props.material = props.animation = False
+ props.material = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object & Data & Materials")
props.object = props.obdata = props.material = True
- props.animation = False
+ props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Materials")
props.material = True
- props.object = props.obdata = props.animation = False
+ props.object = props.obdata = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object Animation")
props.animation = True
- props.object = props.obdata = props.material = False
+ props.object = props.obdata = props.material = props.obdata_animation = False
+
+ props = layout.operator("object.make_single_user", text="Object Data Animation")
+ props.obdata_animation = props.obdata = True
+ props.object = props.material = props.animation = False
class VIEW3D_MT_object_convert(Menu):
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 6c07708b5ef..14ab9f21424 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -50,8 +50,8 @@ bool id_can_have_animdata(const struct ID *id);
/* Get AnimData from the given ID-block */
struct AnimData *BKE_animdata_from_id(struct ID *id);
-/* Add AnimData to the given ID-block */
-struct AnimData *BKE_animdata_add_id(struct ID *id);
+/* Ensure AnimData is present in the ID-block (when supported). */
+struct AnimData *BKE_animdata_ensure_id(struct ID *id);
/* Set active action used by AnimData from the given ID-block */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 9d286b94b04..30f6ad7475d 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 8
+#define BLENDER_FILE_SUBVERSION 9
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index a0aee552759..2c25b940578 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -765,6 +765,7 @@ add_dependencies(bf_blenkernel bf_dna)
if(WITH_GTESTS)
set(TEST_SRC
+ intern/action_test.cc
intern/armature_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 13ca5ecf23c..d55f023d209 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -497,9 +497,8 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
}
/* Reconstruct group channel pointers.
- * Assumes that the channels are still in the proper order, i.e. that channels of the same group
- * are adjacent in the act->channels list. It also assumes that the groups
- * referred to by the FCurves are already in act->groups.
+ * Assumes that the groups referred to by the FCurves are already in act->groups.
+ * Reorders the main channel list to match group order.
*/
void BKE_action_groups_reconstruct(bAction *act)
{
@@ -514,23 +513,30 @@ void BKE_action_groups_reconstruct(bAction *act)
BLI_listbase_clear(&group->channels);
}
- bActionGroup *grp;
- bActionGroup *last_grp = NULL;
- LISTBASE_FOREACH (FCurve *, fcurve, &act->curves) {
- if (fcurve->grp == NULL) {
- continue;
- }
+ /* Sort the channels into the group lists, destroying the act->curves list. */
+ ListBase ungrouped = {NULL, NULL};
- grp = fcurve->grp;
- if (last_grp != grp) {
- /* If this is the first time we see this group, this must be the first channel. */
- grp->channels.first = fcurve;
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcurve, &act->curves) {
+ if (fcurve->grp) {
+ BLI_assert(BLI_findindex(&act->groups, fcurve->grp) >= 0);
+
+ BLI_addtail(&fcurve->grp->channels, fcurve);
+ }
+ else {
+ BLI_addtail(&ungrouped, fcurve);
}
+ }
+
+ /* Recombine into the main list. */
+ BLI_listbase_clear(&act->curves);
- /* This is the last channel, until it's overwritten by a later iteration. */
- grp->channels.last = fcurve;
- last_grp = grp;
+ LISTBASE_FOREACH (bActionGroup *, group, &act->groups) {
+ /* Copy the list header to preserve the pointers in the group. */
+ ListBase tmp = group->channels;
+ BLI_movelisttolist(&act->curves, &tmp);
}
+
+ BLI_movelisttolist(&act->curves, &ungrouped);
}
/* Remove the given channel from all groups */
diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc
new file mode 100644
index 00000000000..cd8751ec358
--- /dev/null
+++ b/source/blender/blenkernel/intern/action_test.cc
@@ -0,0 +1,144 @@
+/*
+ * 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) 2021 Blender Foundation
+ * All rights reserved.
+ */
+
+#include "BKE_action.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+
+#include "BLI_listbase.h"
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+TEST(action_groups, ReconstructGroupsWithReordering)
+{
+ // Construct an Action with three groups.
+ bAction action = {0};
+ FCurve groupAcurve1 = {0};
+ FCurve groupAcurve2 = {0};
+ FCurve groupBcurve1 = {0};
+ FCurve groupBcurve2 = {0};
+ FCurve groupBcurve3 = {0};
+ // Group C has no curves intentionally.
+ FCurve groupDcurve1 = {0};
+ FCurve groupDcurve2 = {0};
+
+ groupAcurve1.rna_path = (char *)"groupAcurve1";
+ groupAcurve2.rna_path = (char *)"groupAcurve2";
+ groupBcurve1.rna_path = (char *)"groupBcurve1";
+ groupBcurve2.rna_path = (char *)"groupBcurve2";
+ groupDcurve1.rna_path = (char *)"groupDcurve1";
+ groupBcurve3.rna_path = (char *)"groupBcurve3";
+ groupDcurve2.rna_path = (char *)"groupDcurve2";
+
+ BLI_addtail(&action.curves, &groupAcurve1);
+ BLI_addtail(&action.curves, &groupAcurve2);
+ BLI_addtail(&action.curves, &groupBcurve1);
+ BLI_addtail(&action.curves, &groupBcurve2);
+ BLI_addtail(&action.curves, &groupDcurve1);
+ BLI_addtail(&action.curves, &groupBcurve3); // <-- The error that should be corrected.
+ BLI_addtail(&action.curves, &groupDcurve2);
+
+ // Introduce another error type, by changing some `prev` pointers.
+ groupBcurve1.prev = NULL;
+ groupBcurve3.prev = &groupBcurve2;
+ groupDcurve1.prev = &groupBcurve3;
+
+ bActionGroup groupA = {0};
+ bActionGroup groupB = {0};
+ bActionGroup groupC = {0};
+ bActionGroup groupD = {0};
+ strcpy(groupA.name, "groupA");
+ strcpy(groupB.name, "groupB");
+ strcpy(groupC.name, "groupC");
+ strcpy(groupD.name, "groupD");
+
+ BLI_addtail(&action.groups, &groupA);
+ BLI_addtail(&action.groups, &groupB);
+ BLI_addtail(&action.groups, &groupC);
+ BLI_addtail(&action.groups, &groupD);
+
+ groupAcurve1.grp = &groupA;
+ groupAcurve2.grp = &groupA;
+ groupBcurve1.grp = &groupB;
+ groupBcurve2.grp = &groupB;
+ groupBcurve3.grp = &groupB;
+ groupDcurve1.grp = &groupD;
+ groupDcurve2.grp = &groupD;
+
+ groupA.channels.first = &groupAcurve1;
+ groupA.channels.last = &groupAcurve2;
+ groupB.channels.first = &groupBcurve1;
+ groupB.channels.last = &groupBcurve3; // The last channel in group B, after group C curve 1.
+ groupD.channels.first = &groupDcurve1;
+ groupD.channels.last = &groupDcurve2;
+
+ EXPECT_EQ(groupA.channels.first, &groupAcurve1);
+ EXPECT_EQ(groupA.channels.last, &groupAcurve2);
+ EXPECT_EQ(groupB.channels.first, &groupBcurve1);
+ EXPECT_EQ(groupB.channels.last, &groupBcurve3);
+ EXPECT_EQ(groupC.channels.first, nullptr);
+ EXPECT_EQ(groupC.channels.last, nullptr);
+ EXPECT_EQ(groupD.channels.first, &groupDcurve1);
+ EXPECT_EQ(groupD.channels.last, &groupDcurve2);
+
+ BKE_action_groups_reconstruct(&action);
+
+ EXPECT_EQ(action.curves.first, &groupAcurve1);
+ EXPECT_EQ(action.curves.last, &groupDcurve2);
+
+ EXPECT_EQ(groupA.prev, nullptr);
+ EXPECT_EQ(groupB.prev, &groupA);
+ EXPECT_EQ(groupC.prev, &groupB);
+ EXPECT_EQ(groupD.prev, &groupC);
+
+ EXPECT_EQ(groupA.next, &groupB);
+ EXPECT_EQ(groupB.next, &groupC);
+ EXPECT_EQ(groupC.next, &groupD);
+ EXPECT_EQ(groupD.next, nullptr);
+
+ EXPECT_EQ(groupA.channels.first, &groupAcurve1);
+ EXPECT_EQ(groupA.channels.last, &groupAcurve2);
+ EXPECT_EQ(groupB.channels.first, &groupBcurve1);
+ EXPECT_EQ(groupB.channels.last, &groupBcurve3);
+ EXPECT_EQ(groupC.channels.first, nullptr);
+ EXPECT_EQ(groupC.channels.last, nullptr);
+ EXPECT_EQ(groupD.channels.first, &groupDcurve1);
+ EXPECT_EQ(groupD.channels.last, &groupDcurve2);
+
+ EXPECT_EQ(groupAcurve1.prev, nullptr);
+ EXPECT_EQ(groupAcurve2.prev, &groupAcurve1);
+ EXPECT_EQ(groupBcurve1.prev, &groupAcurve2);
+ EXPECT_EQ(groupBcurve2.prev, &groupBcurve1);
+ EXPECT_EQ(groupBcurve3.prev, &groupBcurve2);
+ EXPECT_EQ(groupDcurve1.prev, &groupBcurve3);
+ EXPECT_EQ(groupDcurve2.prev, &groupDcurve1);
+
+ EXPECT_EQ(groupAcurve1.next, &groupAcurve2);
+ EXPECT_EQ(groupAcurve2.next, &groupBcurve1);
+ EXPECT_EQ(groupBcurve1.next, &groupBcurve2);
+ EXPECT_EQ(groupBcurve2.next, &groupBcurve3);
+ EXPECT_EQ(groupBcurve3.next, &groupDcurve1);
+ EXPECT_EQ(groupDcurve1.next, &groupDcurve2);
+ EXPECT_EQ(groupDcurve2.next, nullptr);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 4766fc6096b..7e4ab754500 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -89,16 +89,16 @@ bool id_can_have_animdata(const ID *id)
return id_type_can_have_animdata(GS(id->name));
}
-/* Get AnimData from the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate.
+/**
+ * Get #AnimData from the given ID-block.
*/
AnimData *BKE_animdata_from_id(ID *id)
{
- /* only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and extract the
- * AnimData that way
- */
+ /* In order for this to work, we assume that the #AnimData pointer is stored
+ * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
+
+ /* Only some ID-blocks have this info for now, so we cast the types that do
+ * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
return iat->adt;
@@ -106,16 +106,16 @@ AnimData *BKE_animdata_from_id(ID *id)
return NULL;
}
-/* Add AnimData to the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate. Also note that
+/**
+ * Ensure #AnimData exists in the given ID-block (when supported).
*/
-AnimData *BKE_animdata_add_id(ID *id)
+AnimData *BKE_animdata_ensure_id(ID *id)
{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and add the AnimData
- * to it using the template
- */
+ /* In order for this to work, we assume that the #AnimData pointer is stored
+ * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
+
+ /* Only some ID-blocks have this info for now, so we cast the types that do
+ * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
@@ -667,7 +667,7 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
/* get animdata from src, and create for destination (if needed) */
srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_animdata_add_id(dstID);
+ dstAdt = BKE_animdata_ensure_id(dstID);
if (ELEM(NULL, srcAdt, dstAdt)) {
if (G.debug & G_DEBUG) {
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index a1f82b1dcb6..8a70f065e40 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -2087,7 +2087,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check if object has any animation data */
if (ob->nlastrips.first) {
/* Add AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
/* IPO first to take into any non-NLA'd Object Animation */
if (ob->ipo) {
@@ -2109,7 +2109,7 @@ void do_versions_ipos_to_animato(Main *bmain)
}
else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Action first - so that Action name get conserved */
if (ob->action) {
@@ -2133,7 +2133,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check PoseChannels for constraints with local data */
if (ob->pose) {
/* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
@@ -2159,7 +2159,7 @@ void do_versions_ipos_to_animato(Main *bmain)
*/
if (con->ipo) {
/* Verify if there's AnimData block, just in case */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
/* although this was the constraint's local IPO, we still need to provide con
* so that drivers can be added properly...
@@ -2176,7 +2176,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check constraint channels - we need to remove them anyway... */
if (ob->constraintChannels.first) {
/* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
/* get pointer to next Constraint Channel */
@@ -2217,7 +2217,7 @@ void do_versions_ipos_to_animato(Main *bmain)
*/
if (key->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Shapekey data... */
ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL);
@@ -2242,7 +2242,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (ma->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Material data... */
ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL);
@@ -2267,7 +2267,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (wo->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert World data... */
ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL);
@@ -2288,7 +2288,7 @@ void do_versions_ipos_to_animato(Main *bmain)
if (ed && ed->seqbasep) {
Sequence *seq;
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
SEQ_ALL_BEGIN (ed, seq) {
IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL;
@@ -2346,7 +2346,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (te->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Texture data... */
ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL);
@@ -2371,7 +2371,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (ca->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Camera data... */
ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL);
@@ -2396,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (la->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Light data... */
ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL);
@@ -2421,7 +2421,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (cu->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Curve data... */
ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 37c3d9017cd..d8b9b851865 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -2813,7 +2813,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* add new animdata block */
if (!ob->adt) {
- ob->adt = BKE_animdata_add_id(&ob->id);
+ ob->adt = BKE_animdata_ensure_id(&ob->id);
}
/* make a copy of all the drivers (for now), then correct any links that need fixing */
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 2847bc960ad..52d41173a0e 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -28,52 +28,53 @@
extern "C" {
#endif
-void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride);
+void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
-void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir);
+void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
-void _bli_array_permute(void *arr,
- const unsigned int arr_len,
- const size_t arr_stride,
- const unsigned int *order,
- void *arr_temp);
+void _bli_array_permute(
+ void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
-int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
+#define BLI_array_deduplicate_ordered(arr, arr_len) \
+ _bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
+
+int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
-int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
void _bli_array_binary_and(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride);
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride);
#define BLI_array_binary_and(arr, arr_a, arr_b, arr_len) \
(CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_and(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
void _bli_array_binary_or(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride);
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride);
#define BLI_array_binary_or(arr, arr_a, arr_b, arr_len) \
(CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
bool _bli_array_iter_span(const void *arr,
- unsigned int arr_len,
+ uint arr_len,
size_t arr_stride,
bool use_wrap,
bool use_delimit_bounds,
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data,
- unsigned int span_step[2],
- unsigned int *r_span_len);
+ uint span_step[2],
+ uint *r_span_len);
#define BLI_array_iter_span( \
arr, arr_len, use_wrap, use_delimit_bounds, test_fn, user_data, span_step, r_span_len) \
_bli_array_iter_span(arr, \
@@ -86,7 +87,7 @@ bool _bli_array_iter_span(const void *arr,
span_step, \
r_span_len)
-bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride);
+bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
bool _bli_array_iter_spiral_square(const void *arr_v,
diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
index 25fd02b41fb..3051d980d45 100644
--- a/source/blender/blenlib/BLI_enumerable_thread_specific.hh
+++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
@@ -77,17 +77,18 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
* their addresses do not change when the map grows. */
Map<int, std::reference_wrapper<T>> values_;
Vector<std::unique_ptr<T>> owned_values_;
- std::function<T()> initializer_;
+ std::function<void(void *)> initializer_;
public:
using iterator = typename Map<int, std::reference_wrapper<T>>::MutableValueIterator;
- EnumerableThreadSpecific() : initializer_([]() { return T(); })
+ EnumerableThreadSpecific() : initializer_([](void *buffer) { new (buffer) T(); })
{
}
template<typename F>
- EnumerableThreadSpecific(F initializer) : initializer_(std::move(initializer))
+ EnumerableThreadSpecific(F initializer)
+ : initializer_([=](void *buffer) { new (buffer) T(initializer()); })
{
}
@@ -96,11 +97,10 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
const int thread_id = enumerable_thread_specific_utils::thread_id;
std::lock_guard lock{mutex_};
return values_.lookup_or_add_cb(thread_id, [&]() {
- /* `std::make_unique` does not work here if T is non-copyable and non-movable. */
- std::unique_ptr<T> value{new T(initializer_())};
- std::reference_wrapper<T> ref = *value;
- owned_values_.append(std::move(value));
- return ref;
+ T *value = (T *)::operator new(sizeof(T));
+ initializer_(value);
+ owned_values_.append(std::unique_ptr<T>{value});
+ return std::reference_wrapper<T>{*value};
});
}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 25261e82cc9..9a12a7442b7 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -40,11 +40,11 @@
*
* Access via #BLI_array_reverse
*/
-void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
+void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
- const unsigned int arr_half_stride = (arr_len / 2) * arr_stride_uint;
- unsigned int i, i_end;
+ const uint arr_stride_uint = (uint)arr_stride;
+ const uint arr_half_stride = (arr_len / 2) * arr_stride_uint;
+ uint i, i_end;
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
@@ -62,7 +62,7 @@ void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
*
* Access via #BLI_array_wrap
*/
-void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir)
+void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
@@ -88,16 +88,13 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d
*
* Access via #BLI_array_wrap
*/
-void _bli_array_permute(void *arr,
- const unsigned int arr_len,
- const size_t arr_stride,
- const unsigned int *order,
- void *arr_temp)
+void _bli_array_permute(
+ void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{
const size_t len = arr_len * arr_stride;
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const uint arr_stride_uint = (uint)arr_stride;
void *arr_orig;
- unsigned int i;
+ uint i;
if (arr_temp == NULL) {
arr_orig = MEM_mallocN(len, __func__);
@@ -121,16 +118,45 @@ void _bli_array_permute(void *arr,
}
/**
+ * In-place array de-duplication of an ordered array.
+ *
+ * \return The new length of the array.
+ *
+ * Access via #BLI_array_deduplicate_ordered
+ */
+uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
+{
+ if (UNLIKELY(arr_len <= 1)) {
+ return arr_len;
+ }
+
+ const uint arr_stride_uint = (uint)arr_stride;
+ uint j = 0;
+ for (uint i = 0; i < arr_len; i++) {
+ if ((i == j) || (memcmp(POINTER_OFFSET(arr, arr_stride_uint * i),
+ POINTER_OFFSET(arr, arr_stride_uint * j),
+ arr_stride) == 0)) {
+ continue;
+ }
+ j += 1;
+ memcpy(POINTER_OFFSET(arr, arr_stride_uint * j),
+ POINTER_OFFSET(arr, arr_stride_uint * i),
+ arr_stride);
+ }
+ return j + 1;
+}
+
+/**
* Find the first index of an item in an array.
*
* Access via #BLI_array_findindex
*
* \note Not efficient, use for error checks/asserts.
*/
-int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
- for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ for (uint i = 0; i < arr_len; i++, arr_step += arr_stride) {
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
}
@@ -141,10 +167,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
/**
* A version of #BLI_array_findindex that searches from the end of the list.
*/
-int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
- for (unsigned int i = arr_len; i-- != 0;) {
+ for (uint i = arr_len; i-- != 0;) {
arr_step -= arr_stride;
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
@@ -154,7 +180,7 @@ int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stri
}
void _bli_array_binary_and(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride)
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride)
{
char *dst = arr;
const char *src_a = arr_a;
@@ -167,7 +193,7 @@ void _bli_array_binary_and(
}
void _bli_array_binary_or(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride)
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride)
{
char *dst = arr;
const char *src_a = arr_a;
@@ -196,14 +222,14 @@ void _bli_array_binary_or(
* where calculating the length isn't a simple subtraction.
*/
bool _bli_array_iter_span(const void *arr,
- unsigned int arr_len,
+ uint arr_len,
size_t arr_stride,
bool use_wrap,
bool use_delimit_bounds,
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data,
- unsigned int span_step[2],
- unsigned int *r_span_len)
+ uint span_step[2],
+ uint *r_span_len)
{
if (arr_len == 0) {
return false;
@@ -212,11 +238,11 @@ bool _bli_array_iter_span(const void *arr,
return false;
}
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const uint arr_stride_uint = (uint)arr_stride;
const void *item_prev;
bool test_prev;
- unsigned int i_curr;
+ uint i_curr;
if ((span_step[0] == arr_len) && (span_step[1] == arr_len)) {
if (use_wrap) {
@@ -249,11 +275,11 @@ bool _bli_array_iter_span(const void *arr,
while (i_curr < arr_len) {
bool test_curr = test_fn(item_curr, user_data);
if ((test_prev == false) && (test_curr == true)) {
- unsigned int span_len;
- unsigned int i_step_prev = i_curr;
+ uint span_len;
+ uint i_step_prev = i_curr;
if (use_wrap) {
- unsigned int i_step = i_curr + 1;
+ uint i_step = i_curr + 1;
if (UNLIKELY(i_step == arr_len)) {
i_step = 0;
}
@@ -273,7 +299,7 @@ bool _bli_array_iter_span(const void *arr,
}
}
else {
- unsigned int i_step = i_curr + 1;
+ uint i_step = i_curr + 1;
while ((i_step != arr_len) &&
test_fn(POINTER_OFFSET(arr, i_step * arr_stride_uint), user_data)) {
i_step_prev = i_step;
@@ -307,7 +333,7 @@ bool _bli_array_iter_span(const void *arr,
/**
* Simple utility to check memory is zeroed.
*/
-bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_stride)
+bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{
const char *arr_step = (const char *)arr_v;
size_t i = arr_stride * arr_len;
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index dddf8851767..8b8850c7cdb 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -1460,11 +1460,6 @@ static int find_cell_for_point_near_edge(mpq3 p,
return c;
}
-static const Vert *max_x_vert(const Vert *a, const Vert *b)
-{
- return (a->co_exact.x > b->co_exact.x) ? a : b;
-}
-
/**
* Find the ambient cell -- that is, the cell that is outside
* all other cells.
@@ -1492,7 +1487,9 @@ static int find_ambient_cell(const IMesh &tm,
/* First find a vertex with the maximum x value. */
/* Prefer not to populate the verts in the #IMesh just for this. */
const Vert *v_extreme;
-
+ auto max_x_vert = [](const Vert *a, const Vert *b) {
+ return (a->co_exact.x > b->co_exact.x) ? a : b;
+ };
if (component_patches == nullptr) {
v_extreme = threading::parallel_reduce(
tm.face_index_range(),
diff --git a/source/blender/blenlib/tests/BLI_array_utils_test.cc b/source/blender/blenlib/tests/BLI_array_utils_test.cc
index 5d12b8fbd4d..1bf221c5335 100644
--- a/source/blender/blenlib/tests/BLI_array_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_array_utils_test.cc
@@ -189,3 +189,53 @@ TEST(array_utils, BinaryOrInt4Mix)
BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
#undef BINARY_OR_TEST
+
+/* BLI_array_deduplicate_ordered */
+#define DEDUPLICATE_ORDERED_TEST(data, data_cmp) \
+ { \
+ const uint data_len_new = BLI_array_deduplicate_ordered(data, ARRAY_SIZE(data)); \
+ EXPECT_EQ(data_len_new, ARRAY_SIZE(data_cmp)); \
+ EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \
+ /* Ensure running a second time does nothing. */ \
+ const uint data_len_test = BLI_array_deduplicate_ordered(data, data_len_new); \
+ EXPECT_EQ(data_len_test, ARRAY_SIZE(data_cmp)); \
+ EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \
+ } \
+ ((void)0)
+
+TEST(array_utils, DeduplicateOrdered1)
+{
+ int data[] = {0};
+ const int data_cmp[] = {0};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered2)
+{
+ int data[] = {1, 2};
+ const int data_cmp[] = {1, 2};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered2Same)
+{
+ int data[] = {1, 1};
+ const int data_cmp[] = {1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered3Same)
+{
+ int data[] = {1, 1, 1};
+ const int data_cmp[] = {1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered3)
+{
+ int data[] = {3, 3, 2, 2, 1, 1};
+ const int data_cmp[] = {3, 2, 1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+#undef DEDUPLICATE_ORDERED_TEST
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 643c7e9a762..dd5577283c5 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -36,6 +36,7 @@
#include "DNA_modifier_types.h"
#include "DNA_text_types.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_fcurve_driver.h"
@@ -493,17 +494,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) {
+ /* Fix a bug where reordering FCurves and bActionGroups could cause some corruption. Just
+ * reconstruct all the action groups & ensure that the FCurves of a group are continuously
+ * stored (i.e. not mixed with other groups) to be sure. See T89435. */
+ LISTBASE_FOREACH (bAction *, act, &bmain->actions) {
+ BKE_action_groups_reconstruct(act);
+ }
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
@@ -516,4 +513,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 9466be4a300..3978959a425 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -724,7 +724,7 @@ static BMOpDefine bmo_edgenet_fill_def = {
};
/*
- * Edgenet Prepare.
+ * Edge-net Prepare.
*
* Identifies several useful edge loop cases and modifies them so
* they'll become a face when edgenet_fill is called. The cases covered are:
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 51af4d24e52..242b269ed47 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup bmesh
*
- * Edgenet Fill.
+ * Edge-net Fill.
*/
#include <limits.h>
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 1e9adea2615..eb56075e136 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -938,7 +938,7 @@ bool BM_mesh_intersect_edges(
}
if (va_dest == v_other_dest) {
- /* Edge/Edgenet to vertex - we can't split the face. */
+ /* Edge/Edge-net to vertex - we can't split the face. */
break;
}
if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) {
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 9dde73269fc..c3647a39909 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -36,12 +36,12 @@ namespace blender::compositor {
*
* http://www.iryoku.com/smaa/
*
- * This file is based on smaa-cpp:
+ * This file is based on SMAA-CPP:
*
* https://github.com/iRi-E/smaa-cpp
*
* Currently only SMAA 1x mode is provided, so the operation will be done
- * with no spatial multisampling nor temporal supersampling.
+ * with no spatial multi-sampling nor temporal super-sampling.
*
* NOTE: This program assumes the screen coordinates are DirectX style, so
* the vertical direction is upside-down. "top" and "bottom" actually mean
diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c
index 2522a445d8e..1a236e4f2a8 100644
--- a/source/blender/draw/engines/image/image_engine.c
+++ b/source/blender/draw/engines/image/image_engine.c
@@ -31,6 +31,7 @@
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
+#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "ED_image.h"
@@ -222,19 +223,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
}
else /* RGB */ {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
}
}
if (space_type == SPACE_NODE) {
@@ -248,19 +260,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser
copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
}
else if ((snode->flag & SNODE_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((snode->flag & SNODE_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
}
else if ((snode->flag & SNODE_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
}
else /* RGB */ {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
}
}
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 62742d082ca..6f5e041fa79 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1645,7 +1645,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
drw_engines_draw_scene();
- /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */
+ /* Fix 3D view "lagging" on APPLE and WIN32+NVIDIA. (See T56996, T61474) */
GPU_flush();
DRW_stats_reset();
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 76b6ce54d29..8f8c1c067d4 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1283,6 +1283,9 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
else {
group_fcurves_last->next->prev = group_fcurves_first->prev;
}
+
+ /* Clear links pointing outside the per-group list. */
+ group_fcurves_first->prev = group_fcurves_last->next = NULL;
}
/* Initialize memory for temp-group */
@@ -1337,24 +1340,12 @@ static void join_groups_action_temp(bAction *act)
if (agrp->flag & AGRP_TEMP) {
LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) {
fcu->grp = NULL;
- if (fcu == agrp->channels.last) {
- break;
- }
}
BLI_remlink(&act->groups, agrp);
break;
}
}
-
- /* BLI_movelisttolist() doesn't touch first->prev and last->next pointers in its "dst" list.
- * Ensure that after the reshuffling the list is properly terminated. */
- if (!BLI_listbase_is_empty(&act->curves)) {
- FCurve *act_fcurves_first = act->curves.first;
- act_fcurves_first->prev = NULL;
- FCurve *act_fcurves_last = act->curves.last;
- act_fcurves_last->next = NULL;
- }
}
/* Change the order of anim-channels within action
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 16eb2f6b6f2..bfaa76b3bf9 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -80,7 +80,7 @@ FCurve *verify_driver_fcurve(ID *id,
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 864d97c9ea9..0a499232ba9 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -142,7 +142,7 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 6d22da2c2bc..8ae74fbfafa 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1845,7 +1845,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
* ready to be moved around to re-time the sound and/or make new sound clips. */
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_animdata_add_id(&ob->id);
+ AnimData *adt = BKE_animdata_ensure_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data);
strip->start = CFRA;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 30f75e9a150..d7177eabcba 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2061,6 +2061,23 @@ static void single_object_action_users(
FOREACH_OBJECT_FLAG_END;
}
+static void single_objectdata_action_users(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
+{
+ FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
+ if (!ID_IS_LINKED(ob) && ob->data != NULL) {
+ ID *id_obdata = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(id_obdata);
+ ID *id_act = (ID *)adt->action;
+ if (id_act && id_act->us > 1) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_animdata_copy_id_action(bmain, id_obdata);
+ }
+ }
+ }
+ FOREACH_OBJECT_FLAG_END;
+}
+
static void single_mat_users(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
{
@@ -2643,6 +2660,10 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_object_action_users(bmain, scene, view_layer, v3d, flag);
}
+ if (RNA_boolean_get(op->ptr, "obdata_animation")) {
+ single_objectdata_action_users(bmain, scene, view_layer, v3d, flag);
+ }
+
BKE_main_id_newptr_and_tag_clear(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2684,8 +2705,16 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block");
- RNA_def_boolean(
- ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "animation",
+ 0,
+ "Object Animation",
+ "Make object animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "obdata_animation",
+ 0,
+ "Object Data Animation",
+ "Make object data (mesh, curve etc.) animation data local to each object");
}
/** \} */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 51b897ce5a3..0498964c549 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -874,7 +874,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
/* operate on selected objects... */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
/* ensure that object has AnimData... that's all */
- BKE_animdata_add_id(&ob->id);
+ BKE_animdata_ensure_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 0c1463e69c1..80d3b43bf6b 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -40,7 +40,6 @@ set(INC
set(SRC
drawnode.cc
node_add.cc
- node_buttons.c
node_draw.cc
node_edit.cc
node_geometry_attribute_search.cc
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
deleted file mode 100644
index a55cc21fb16..00000000000
--- a/source/blender/editors/space_node/node_buttons.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup spnode
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_node_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_node.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-
-#include "ED_screen.h"
-
-#include "UI_resources.h"
-
-#include "node_intern.h" /* own include */
-
-/* ******************* node space & buttons ************** */
-
-#if 0
-/* poll for active nodetree */
-static bool active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree);
-}
-#endif
-
-static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree && G.debug_value == 777);
-}
-
-static void node_sockets_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
- bNode *node = nodeGetActive(ntree);
- if (node == NULL) {
- return;
- }
-
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- char name[UI_MAX_NAME_STR];
- BLI_snprintf(name, sizeof(name), "%s:", socket->name);
-
- uiLayout *split = uiLayoutSplit(panel->layout, 0.35f, false);
- uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, (bContext *)C, ntree, node, socket);
- }
-}
-
-static bool node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->edittree &&
- (snode->edittree->inputs.first || snode->edittree->outputs.first));
-}
-
-static bNodeSocket *node_tree_find_active_socket(bNodeTree *ntree, const eNodeSocketInOut in_out)
-{
- ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
- LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
- if (socket->flag & SELECT) {
- return socket;
- }
- }
- return NULL;
-}
-
-static void draw_socket_list(const bContext *C,
- uiLayout *layout,
- bNodeTree *ntree,
- const eNodeSocketInOut in_out)
-{
- PointerRNA tree_ptr;
- RNA_id_pointer_create((ID *)ntree, &tree_ptr);
-
- uiLayout *split = uiLayoutRow(layout, false);
- uiLayout *list_col = uiLayoutColumn(split, true);
- uiTemplateList(list_col,
- (bContext *)C,
- "NODE_UL_interface_sockets",
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "active_input" : "active_output",
- NULL,
- 0,
- 0,
- 0,
- 0,
- false,
- false);
- PointerRNA opptr;
- uiLayout *ops_col = uiLayoutColumn(split, false);
- uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_ADD, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
- ot = WM_operatortype_find("NODE_OT_tree_socket_remove", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_REMOVE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- uiItemS(ops_col);
-
- uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
- ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 1);
- RNA_enum_set(&opptr, "in_out", in_out);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 2);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- bNodeSocket *socket = node_tree_find_active_socket(ntree, in_out);
- if (socket != NULL) {
- PointerRNA socket_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, socket, &socket_ptr);
-
- {
- /* Mimicking property split */
- uiLayoutSetPropSep(layout, false);
- uiLayoutSetPropDecorate(layout, false);
- uiLayout *layout_row = uiLayoutRow(layout, true);
- uiLayout *layout_split = uiLayoutSplit(layout_row, 0.4f, true);
-
- uiLayout *label_column = uiLayoutColumn(layout_split, true);
- uiLayoutSetAlignment(label_column, UI_LAYOUT_ALIGN_RIGHT);
- /* Menu to change the socket type. */
- uiItemL(label_column, "Type", ICON_NONE);
-
- uiLayout *property_row = uiLayoutRow(layout_split, true);
-
- PointerRNA props_ptr;
- uiItemMenuEnumFullO(property_row,
- (bContext *)C,
- "NODE_OT_tree_socket_change_type",
- "socket_type",
- nodeSocketTypeLabel(socket->typeinfo),
- ICON_NONE,
- &props_ptr);
- RNA_enum_set(&props_ptr, "in_out", in_out);
- }
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- uiItemR(layout, &socket_ptr, "name", 0, NULL, ICON_NONE);
-
- /* Display descriptions only for Geometry Nodes, since it's only used in the modifier panel. */
- if (ntree->type == NTREE_GEOMETRY) {
- uiItemR(layout, &socket_ptr, "description", 0, NULL, ICON_NONE);
- }
-
- if (socket->typeinfo->interface_draw) {
- socket->typeinfo->interface_draw((bContext *)C, layout, &socket_ptr);
- }
- }
-}
-
-static void node_tree_interface_inputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_IN);
-}
-
-static void node_tree_interface_outputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_OUT);
-}
-
-/* ******************* node buttons registration ************** */
-
-void node_buttons_register(ARegionType *art)
-{
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_sockets");
- strcpy(pt->category, N_("Node"));
- strcpy(pt->label, N_("Sockets"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_sockets_panel;
- pt->poll = node_sockets_poll;
- pt->flag |= PANEL_TYPE_DEFAULT_CLOSED;
- BLI_addtail(&art->paneltypes, pt);
- }
-
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Inputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_inputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Outputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_outputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
-}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index ab63531ff49..a6901c21862 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -155,6 +155,9 @@ static void attribute_search_update_fn(
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
{
+ if (item_v == nullptr) {
+ return;
+ }
AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v);
GeometryAttributeInfo *item = (GeometryAttributeInfo *)item_v;
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index fe550242dbe..09e5a110a45 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -140,9 +140,6 @@ void node_to_view(const struct bNode *node, float x, float y, float *rx, float *
void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
-/* node_buttons.c */
-void node_buttons_register(struct ARegionType *art);
-
/* node_toolbar.c */
void node_toolbar_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 68ba21201d0..ff848a7bb95 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -1098,8 +1098,6 @@ void ED_spacetype_node(void)
art->draw = node_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_buttons_register(art);
-
/* regions: toolbar */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index dcd4ff8df36..2e203d06b12 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1152,7 +1152,7 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = view_layer->basact->object;
ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
@@ -1568,7 +1568,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
case B_TRANSFORM_PANEL_MEDIAN:
if (ob) {
v3d_editvertex_buts(NULL, v3d, ob, 1.0);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
break;
case B_TRANSFORM_PANEL_DIMS:
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index e2fa0fdc6a5..5752837c40f 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -122,7 +122,7 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
{FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
{FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
- {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
+ {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction (toggle)"},
{FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision", ""},
{FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision (Off)", ""},
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 613f58a8143..09936b41a74 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -98,9 +98,10 @@ enum {
WALK_MODAL_JUMP,
WALK_MODAL_JUMP_STOP,
WALK_MODAL_TELEPORT,
- WALK_MODAL_TOGGLE,
+ WALK_MODAL_GRAVITY_TOGGLE,
WALK_MODAL_ACCELERATE,
WALK_MODAL_DECELERATE,
+ WALK_MODAL_AXIS_LOCK_Z,
};
enum {
@@ -129,6 +130,18 @@ typedef enum eWalkGravityState {
WALK_GRAVITY_STATE_ON,
} eWalkGravityState;
+/* Relative view axis z axis locking. */
+typedef enum eWalkLockState {
+ /* Disabled. */
+ WALK_AXISLOCK_STATE_OFF = 0,
+
+ /* Moving. */
+ WALK_AXISLOCK_STATE_ACTIVE = 2,
+
+ /* Done moving, it cannot be activated again. */
+ WALK_AXISLOCK_STATE_DONE = 3,
+} eWalkLockState;
+
/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
@@ -164,7 +177,9 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
{WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump (Off)", "Stop pushing jump"},
- {WALK_MODAL_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+ {WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+
+ {WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"},
{0, NULL, 0, NULL, NULL},
};
@@ -292,6 +307,10 @@ typedef struct WalkInfo {
/** To use for fast/slow speeds. */
float speed_factor;
+ eWalkLockState zlock;
+ /** Nicer dynamics. */
+ float zlock_momentum;
+
struct SnapObjectContext *snap_context;
struct View3DCameraControl *v3d_camera_control;
@@ -540,6 +559,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->jump_height = U.walk_navigation.jump_height;
walk->speed = U.walk_navigation.walk_speed;
walk->speed_factor = U.walk_navigation.walk_speed_factor;
+ walk->zlock = WALK_AXISLOCK_STATE_OFF;
walk->gravity_state = WALK_GRAVITY_STATE_OFF;
@@ -939,7 +959,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
#undef JUMP_TIME_MAX
#undef JUMP_SPEED_MIN
- case WALK_MODAL_TOGGLE:
+ case WALK_MODAL_GRAVITY_TOGGLE:
if (walk->navigation_mode == WALK_MODE_GRAVITY) {
walk_navigation_mode_set(walk, WALK_MODE_FREE);
}
@@ -947,6 +967,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
}
break;
+
+ case WALK_MODAL_AXIS_LOCK_Z:
+ if (walk->zlock != WALK_AXISLOCK_STATE_DONE) {
+ walk->zlock = WALK_AXISLOCK_STATE_ACTIVE;
+ walk->zlock_momentum = 0.0f;
+ }
+ break;
}
}
}
@@ -986,6 +1013,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
+#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
+#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
RegionView3D *rv3d = walk->rv3d;
ARegion *region = walk->region;
@@ -1020,20 +1049,25 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* Should we redraw? */
if ((walk->active_directions) || moffset[0] || moffset[1] ||
- walk->teleport.state == WALK_TELEPORT_STATE_ON ||
- walk->gravity_state != WALK_GRAVITY_STATE_OFF || is_confirm) {
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE ||
+ walk->gravity_state != WALK_GRAVITY_STATE_OFF ||
+ walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm) {
float dvec_tmp[3];
/* time how fast it takes for us to redraw,
* this is so simple scenes don't walk too fast */
double time_current;
float time_redraw;
+ float time_redraw_clamped;
#ifdef NDOF_WALK_DRAW_TOOMUCH
walk->redraw = 1;
#endif
time_current = PIL_check_seconds_timer();
time_redraw = (float)(time_current - walk->time_lastdraw);
+ /* Clamp redraw time to avoid jitter in roll correction. */
+ time_redraw_clamped = min_ff(0.05f, time_redraw);
+
walk->time_lastdraw = time_current;
/* base speed in m/s */
@@ -1126,6 +1160,32 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
axis_angle_to_quat_single(tmp_quat, 'Z', x);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
}
+
+ if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) {
+ float upvec[3];
+ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
+ mul_m3_v3(mat, upvec);
+
+ /* Make sure we have some z rolling. */
+ if (fabsf(upvec[2]) > 0.00001f) {
+ float roll = upvec[2] * 5.0f;
+ /* Rotate the view about this axis. */
+ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
+ mul_m3_v3(mat, upvec);
+ /* Rotate about the relative up vec. */
+ axis_angle_to_quat(tmp_quat,
+ upvec,
+ roll * time_redraw_clamped * walk->zlock_momentum *
+ WALK_ZUP_CORRECT_FAC);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+ walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL;
+ }
+ else {
+ /* Lock fixed, don't need to check it ever again. */
+ walk->zlock = WALK_AXISLOCK_STATE_DONE;
+ }
+ }
}
/* WASD - 'move' translation code */
@@ -1316,7 +1376,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
- walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
+ walk->need_rotation_keyframe |= (moffset[0] || moffset[1] ||
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE);
walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
walkMoveCamera(
C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 90f6beb2f89..a9f50f08cc7 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -205,11 +205,18 @@ static void bakeModifier(Main *UNUSED(bmain),
}
if (!gpd->runtime.lineart_cache) {
+ /* Only calculate for this modifier, thus no need to get maximum values from all line art
+ * modifiers in the stack. */
+ lmd->edge_types_override = lmd->edge_types;
+ lmd->level_end_override = lmd->level_end;
+
MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
MOD_lineart_destroy_render_data(lmd);
}
generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
+
+ MOD_lineart_clear_cache(&gpd->runtime.lineart_cache);
}
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
@@ -331,7 +338,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
- const bool use_cache = RNA_boolean_get(ptr, "use_cached_result");
+ const bool use_cache = RNA_boolean_get(ptr, "use_cache");
const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
uiLayoutSetEnabled(layout, !is_baked);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 499b5538ad8..694636f0c94 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -772,7 +772,7 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_pro
static AnimData *rna_ID_animation_data_create(ID *id, Main *bmain)
{
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
DEG_relations_tag_update(bmain);
return adt;
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 0afb9da9547..5c363a3e6b6 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3205,7 +3205,7 @@ static void rna_NodeSocketInterfaceStandard_draw(ID *id,
struct uiLayout *layout)
{
PointerRNA ptr;
- RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr);
+ RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr);
sock->typeinfo->interface_draw(C, layout, &ptr);
}
@@ -3215,7 +3215,7 @@ static void rna_NodeSocketInterfaceStandard_draw_color(ID *id,
float r_color[4])
{
PointerRNA ptr;
- RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr);
+ RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr);
sock->typeinfo->interface_draw_color(C, &ptr, r_color);
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 56deb873611..11110dd154a 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2106,7 +2106,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
switch (saction->mode) {
case SACTCONT_ACTION:
/* TODO: context selector could help decide this with more control? */
- adt = BKE_animdata_add_id(&obact->id);
+ adt = BKE_animdata_ensure_id(&obact->id);
id = &obact->id;
break;
case SACTCONT_SHAPEKEY: {
@@ -2114,7 +2114,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
if (key == NULL) {
return;
}
- adt = BKE_animdata_add_id(&key->id);
+ adt = BKE_animdata_ensure_id(&key->id);
id = &key->id;
break;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index a5bd41c23e4..a2fcbe35dcc 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -1028,14 +1028,13 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (do_rim) {
uint i;
- /* bugger, need to re-calculate the normals for the new edge faces.
+ /* NOTE(campbell): Unfortunately re-calculate the normals for the new edge faces is necessary.
* This could be done in many ways, but probably the quickest way
* is to calculate the average normals for side faces only.
* Then blend them with the normals of the edge verts.
*
- * at the moment its easiest to allocate an entire array for every vertex,
- * even though we only need edge verts - campbell
- */
+ * At the moment its easiest to allocate an entire array for every vertex,
+ * even though we only need edge verts. */
#define SOLIDIFY_SIDE_NORMALS
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 0ae4def4b67..6266126a7b0 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -210,7 +210,7 @@ DefNode(CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIPS
DefNode(CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" )
DefNode(CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" )
DefNode(CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" )
-DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" )
+DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "Switch View", "" )
DefNode(CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" )
DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" )
DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 04a7fc7e5df..419a7af1ba0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -95,7 +95,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
spline->resize(2);
MutableSpan<float3> positions = spline->positions();
positions[0] = start;
- positions[1] = direction.normalized() * length;
+ positions[1] = direction.normalized() * length + start;
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index c1ae0b05fcd..560f8e33585 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -287,7 +287,7 @@ class Report:
-moz-background-size:50px 50px;
background-size:50px 50px;
- -webkit-background-size:50px 51px; /* override value for shitty webkit */
+ -webkit-background-size:50px 51px; /* Override value for silly webkit. */
background-position:0 0, 25px 0, 25px -25px, 0px 25px;
}}