diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2021-07-11 19:56:43 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2021-07-11 19:56:43 +0300 |
commit | d947b012f7492b5f9bfe80ad9de8c57ad581d6d6 (patch) | |
tree | 6345d890acdd9176ab434102edca5d17264b672d | |
parent | 955d3a517a95fd9d87e9bdc0d2f50665caf4b1ec (diff) | |
parent | 2289e26fa306c3edc60a6b5b776646c6fd1c33dc (diff) |
Merge branch 'master' into temp-gpencil-bezier-stroke-typetemp-gpencil-bezier-stroke-type
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; }} |