From 9cc4861e6f7d18b9426ffc871857d6bd613a252a Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 1 Feb 2022 18:17:51 -0500 Subject: Compositor: Combine and Separate XYZ Node We have this node for shader and geometry nodes. Compositor can also work with vectors, and this can help with that. Reviewed By: manzanilla Maniphest Tasks: T95385 Differential Revision: https://developer.blender.org/D12919 --- release/scripts/startup/nodeitems_builtins.py | 2 + source/blender/blenkernel/BKE_node.h | 2 + source/blender/blenkernel/intern/node.cc | 2 + source/blender/compositor/CMakeLists.txt | 4 ++ source/blender/compositor/intern/COM_Converter.cc | 8 +++ .../blender/compositor/nodes/COM_CombineXYZNode.cc | 55 +++++++++++++++++ .../blender/compositor/nodes/COM_CombineXYZNode.h | 36 +++++++++++ .../compositor/nodes/COM_SeparateXYZNode.cc | 63 +++++++++++++++++++ .../blender/compositor/nodes/COM_SeparateXYZNode.h | 36 +++++++++++ source/blender/makesrna/RNA_access.h | 2 + source/blender/nodes/NOD_composite.h | 2 + source/blender/nodes/NOD_static_types.h | 2 + source/blender/nodes/composite/CMakeLists.txt | 1 + .../composite/nodes/node_composite_sepcomb_xyz.cc | 71 ++++++++++++++++++++++ 14 files changed, 286 insertions(+) create mode 100644 source/blender/compositor/nodes/COM_CombineXYZNode.cc create mode 100644 source/blender/compositor/nodes/COM_CombineXYZNode.h create mode 100644 source/blender/compositor/nodes/COM_SeparateXYZNode.cc create mode 100644 source/blender/compositor/nodes/COM_SeparateXYZNode.h create mode 100644 source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index b841cb5dd13..4b48f5f0680 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -547,6 +547,8 @@ compositor_node_categories = [ NodeItem("CompositorNodeCombYUVA"), NodeItem("CompositorNodeSepYCCA"), NodeItem("CompositorNodeCombYCCA"), + NodeItem("CompositorNodeSeparateXYZ"), + NodeItem("CompositorNodeCombineXYZ"), NodeItem("CompositorNodeSwitchView"), NodeItem("CompositorNodeConvertColorSpace"), ]), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 16d8ba2e6dd..d583b5f0648 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1291,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define CMP_NODE_POSTERIZE 327 #define CMP_NODE_CONVERT_COLOR_SPACE 328 #define CMP_NODE_SCENE_TIME 329 +#define CMP_NODE_SEPARATE_XYZ 330 +#define CMP_NODE_COMBINE_XYZ 331 /* channel toggles */ #define CMP_CHAN_RGB 1 diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 40d0c24c9af..0677b1adb6d 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4503,6 +4503,8 @@ static void registerCompositNodes() register_node_type_cmp_sepycca(); register_node_type_cmp_combycca(); register_node_type_cmp_premulkey(); + register_node_type_cmp_separate_xyz(); + register_node_type_cmp_combine_xyz(); register_node_type_cmp_diff_matte(); register_node_type_cmp_distance_matte(); diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 025e114cb52..2f473ef2945 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -274,10 +274,14 @@ set(SRC # converter nodes nodes/COM_CombineColorNode.cc nodes/COM_CombineColorNode.h + nodes/COM_CombineXYZNode.cc + nodes/COM_CombineXYZNode.h nodes/COM_IDMaskNode.cc nodes/COM_IDMaskNode.h nodes/COM_SeparateColorNode.cc nodes/COM_SeparateColorNode.h + nodes/COM_SeparateXYZNode.cc + nodes/COM_SeparateXYZNode.h nodes/COM_MapRangeNode.cc nodes/COM_MapRangeNode.h diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index 6cf6c698a2f..d0b3ae74446 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -44,6 +44,7 @@ #include "COM_ColorSpillNode.h" #include "COM_ColorToBWNode.h" #include "COM_CombineColorNode.h" +#include "COM_CombineXYZNode.h" #include "COM_CompositorNode.h" #include "COM_ConvertAlphaNode.h" #include "COM_ConvertColorSpaceNode.h" @@ -96,6 +97,7 @@ #include "COM_ScaleOperation.h" #include "COM_SceneTimeNode.h" #include "COM_SeparateColorNode.h" +#include "COM_SeparateXYZNode.h" #include "COM_SetAlphaNode.h" #include "COM_SetValueOperation.h" #include "COM_SplitViewerNode.h" @@ -434,6 +436,12 @@ Node *COM_convert_bnode(bNode *b_node) case CMP_NODE_CONVERT_COLOR_SPACE: node = new ConvertColorSpaceNode(b_node); break; + case CMP_NODE_SEPARATE_XYZ: + node = new SeparateXYZNode(b_node); + break; + case CMP_NODE_COMBINE_XYZ: + node = new CombineXYZNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.cc b/source/blender/compositor/nodes/COM_CombineXYZNode.cc new file mode 100644 index 00000000000..2b71b94e192 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CombineXYZNode.cc @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_CombineXYZNode.h" + +#include "COM_ConvertOperation.h" + +namespace blender::compositor { + +CombineXYZNode::CombineXYZNode(bNode *editor_node) : Node(editor_node) +{ +} + +void CombineXYZNode::convert_to_operations(NodeConverter &converter, + const CompositorContext &UNUSED(context)) const +{ + NodeInput *input_x_socket = this->get_input_socket(0); + NodeInput *input_y_socket = this->get_input_socket(1); + NodeInput *input_z_socket = this->get_input_socket(2); + NodeOutput *output_socket = this->get_output_socket(0); + + CombineChannelsOperation *operation = new CombineChannelsOperation(); + if (input_x_socket->is_linked()) { + operation->set_canvas_input_index(0); + } + else if (input_y_socket->is_linked()) { + operation->set_canvas_input_index(1); + } + else { + operation->set_canvas_input_index(2); + } + converter.add_operation(operation); + + converter.map_input_socket(input_x_socket, operation->get_input_socket(0)); + converter.map_input_socket(input_y_socket, operation->get_input_socket(1)); + converter.map_input_socket(input_z_socket, operation->get_input_socket(2)); + converter.map_output_socket(output_socket, operation->get_output_socket()); +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.h b/source/blender/compositor/nodes/COM_CombineXYZNode.h new file mode 100644 index 00000000000..c3bb69b03ed --- /dev/null +++ b/source/blender/compositor/nodes/COM_CombineXYZNode.h @@ -0,0 +1,36 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_Node.h" + +namespace blender::compositor { + +/** + * \brief SeparateXYZNode + * \ingroup Node + */ +class CombineXYZNode : public Node { + public: + CombineXYZNode(bNode *editor_node); + void convert_to_operations(NodeConverter &converter, + const CompositorContext &context) const override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.cc b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc new file mode 100644 index 00000000000..749116d6217 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc @@ -0,0 +1,63 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_SeparateXYZNode.h" + +#include "COM_ConvertOperation.h" + +namespace blender::compositor { + +SeparateXYZNode::SeparateXYZNode(bNode *editor_node) : Node(editor_node) +{ + /* pass */ +} + +void SeparateXYZNode::convert_to_operations(NodeConverter &converter, + const CompositorContext &UNUSED(context)) const +{ + NodeInput *vector_socket = this->get_input_socket(0); + NodeOutput *output_x_socket = this->get_output_socket(0); + NodeOutput *output_y_socket = this->get_output_socket(1); + NodeOutput *output_z_socket = this->get_output_socket(2); + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(0); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_x_socket, operation->get_output_socket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(1); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_y_socket, operation->get_output_socket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(2); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_z_socket, operation->get_output_socket(0)); + } +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.h b/source/blender/compositor/nodes/COM_SeparateXYZNode.h new file mode 100644 index 00000000000..1efa017d9e3 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.h @@ -0,0 +1,36 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_Node.h" + +namespace blender::compositor { + +/** + * \brief SeparateXYZNode + * \ingroup Node + */ +class SeparateXYZNode : public Node { + public: + SeparateXYZNode(bNode *editor_node); + void convert_to_operations(NodeConverter &converter, + const CompositorContext &context) const override; +}; + +} // namespace blender::compositor diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 1ade964854d..a0d45ee4247 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -143,6 +143,7 @@ extern StructRNA RNA_CompositorNodeCombHSVA; extern StructRNA RNA_CompositorNodeCombRGBA; extern StructRNA RNA_CompositorNodeCombYCCA; extern StructRNA RNA_CompositorNodeCombYUVA; +extern StructRNA RNA_CompositorNodeCombineXYZ; extern StructRNA RNA_CompositorNodeComposite; extern StructRNA RNA_CompositorNodeCornerPin; extern StructRNA RNA_CompositorNodeCrop; @@ -187,6 +188,7 @@ extern StructRNA RNA_CompositorNodeRLayers; extern StructRNA RNA_CompositorNodeRotate; extern StructRNA RNA_CompositorNodeScale; extern StructRNA RNA_CompositorNodeSceneTime; +extern StructRNA RNA_CompositorNodeSeparateXYZ; extern StructRNA RNA_CompositorNodeSepHSVA; extern StructRNA RNA_CompositorNodeSepRGBA; extern StructRNA RNA_CompositorNodeSepYCCA; diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 82faccc2c2d..71acc738472 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -140,6 +140,8 @@ void register_node_type_cmp_pixelate(void); void register_node_type_cmp_trackpos(void); void register_node_type_cmp_planetrackdeform(void); void register_node_type_cmp_cornerpin(void); +void register_node_type_cmp_separate_xyz(void); +void register_node_type_cmp_combine_xyz(void); void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node); void node_cmp_rlayers_register_pass(struct bNodeTree *ntree, diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 8cbde6adcad..8fd71a978e3 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -230,6 +230,8 @@ DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIAL DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" ) DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" ) DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" ) +DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" ) +DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt index dddc3f33dca..8581ab7f82f 100644 --- a/source/blender/nodes/composite/CMakeLists.txt +++ b/source/blender/nodes/composite/CMakeLists.txt @@ -110,6 +110,7 @@ set(SRC nodes/node_composite_sepcomb_rgba.cc nodes/node_composite_sepcomb_ycca.cc nodes/node_composite_sepcomb_yuva.cc + nodes/node_composite_sepcomb_xyz.cc nodes/node_composite_setalpha.cc nodes/node_composite_split_viewer.cc nodes/node_composite_stabilize2d.cc diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc new file mode 100644 index 00000000000..5dfcf5dca1e --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc @@ -0,0 +1,71 @@ +/* + * 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. + */ + +/** \file + * \ingroup cmpnodes + */ + +#include "node_composite_util.hh" + +/* **************** SEPARATE XYZ ******************** */ +namespace blender::nodes { + +static void cmp_node_separate_xyz_declare(NodeDeclarationBuilder &b) +{ + b.add_input("Vector").min(-10000.0f).max(10000.0f); + b.add_output("X"); + b.add_output("Y"); + b.add_output("Z"); +} + +} // namespace blender::nodes + +void register_node_type_cmp_separate_xyz() +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_XYZ, "Separate XYZ", NODE_CLASS_CONVERTER); + ntype.declare = blender::nodes::cmp_node_separate_xyz_declare; + + nodeRegisterType(&ntype); +} + +/* **************** COMBINE XYZ ******************** */ + +namespace blender::nodes { + +static void cmp_node_combine_xyz_declare(NodeDeclarationBuilder &b) +{ + b.add_input("X").min(-10000.0f).max(10000.0f); + b.add_input("Y").min(-10000.0f).max(10000.0f); + b.add_input("Z").min(-10000.0f).max(10000.0f); + b.add_output("Vector"); +} + +} // namespace blender::nodes + +void register_node_type_cmp_combine_xyz() +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_COMBINE_XYZ, "Combine XYZ", NODE_CLASS_CONVERTER); + ntype.declare = blender::nodes::cmp_node_combine_xyz_declare; + + nodeRegisterType(&ntype); +} -- cgit v1.2.3 From 811606a0640f93eca3249a3f15c5a4e61922abeb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 13:10:26 +1100 Subject: Cleanup: shadow warning, remove unused flags --- source/blender/editors/space_view3d/view3d_intern.h | 7 ------- source/blender/editors/transform/transform_gizmo_3d.c | 2 -- 2 files changed, 9 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 6a1a09df316..1ef737bc84b 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -40,13 +40,6 @@ struct wmKeyConfig; struct wmOperatorType; struct wmWindowManager; -/* drawing flags: */ -enum { - DRAW_PICKING = (1 << 0), - DRAW_CONSTCOLOR = (1 << 1), - DRAW_SCENESET = (1 << 2), -}; - /* view3d_header.c */ void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index c1f36951f64..c0572478481 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -954,8 +954,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob_iter = objects[ob_index]; const bool use_mat_local = params->use_local_axis && (ob_iter != ob); - bPoseChannel *pchan; - /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ const int mode = TFM_ROTATION; -- cgit v1.2.3 From d82372aee3a473226ea6b565f09cebd54310a4cd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 13:15:43 +1100 Subject: Cleanup: spelling in comments --- .../blenkernel/intern/image_partial_update.cc | 3 +- source/blender/blenkernel/intern/modifier.c | 4 +- .../draw/engines/image/image_drawing_mode.hh | 21 +++++----- .../draw/intern/draw_cache_impl_subdivision.cc | 4 +- source/blender/editors/gpencil/gpencil_edit.c | 2 +- source/blender/gpu/GPU_select.h | 2 +- source/blender/gpu/GPU_texture.h | 3 +- .../io/wavefront_obj/exporter/obj_export_io.hh | 8 ++-- source/blender/makesrna/intern/rna_asset.c | 2 +- source/blender/makesrna/intern/rna_internal.h | 5 ++- source/blender/render/intern/texture_margin.cc | 45 +++++++++++++--------- source/blender/sequencer/intern/strip_add.c | 2 +- tests/python/bl_keymap_validate.py | 2 +- 13 files changed, 57 insertions(+), 46 deletions(-) diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc index ddf0e18ff9b..876e5276e5a 100644 --- a/source/blender/blenkernel/intern/image_partial_update.cc +++ b/source/blender/blenkernel/intern/image_partial_update.cc @@ -273,7 +273,8 @@ struct TileChangeset { const int previous_chunk_len = chunk_dirty_flags_.size(); chunk_dirty_flags_.resize(chunk_len); - /* Fast exit. When the changeset was already empty no need to re-init the chunk_validity. */ + /* Fast exit. When the changeset was already empty no need to + * re-initialize the chunk_validity. */ if (!has_dirty_chunks()) { return; } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index e1fd8ff45d1..bdf2568287b 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -1182,8 +1182,8 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase) #if 0 CollisionModifierData *collmd = (CollisionModifierData *)md; - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this + /* TODO: CollisionModifier should use pointcache + * + have proper reset events before enabling this. */ writestruct(wd, DATA, MVert, collmd->numverts, collmd->x); writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew); writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces); diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index dfff93b9429..3be34ef6acb 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -227,8 +227,7 @@ template class ScreenSpaceDrawingMode : public AbstractD GPUTexture *texture = info.texture; const float texture_width = GPU_texture_width(texture); const float texture_height = GPU_texture_height(texture); - // TODO - // early bound check. + /* TODO: early bound check. */ ImageTileWrapper tile_accessor(iterator.tile_data.tile); float tile_offset_x = static_cast(tile_accessor.get_tile_x_offset()); float tile_offset_y = static_cast(tile_accessor.get_tile_y_offset()); @@ -253,9 +252,9 @@ template class ScreenSpaceDrawingMode : public AbstractD if (!region_overlap) { continue; } - // convert the overlapping region to texel space and to ss_pixel space... - // TODO: first convert to ss_pixel space as integer based. and from there go back to texel - // space. But perhaps this isn't needed and we could use an extraction offset somehow. + /* Convert the overlapping region to texel space and to ss_pixel space... + * TODO: first convert to ss_pixel space as integer based. and from there go back to texel + * space. But perhaps this isn't needed and we could use an extraction offset somehow. */ rcti gpu_texture_region_to_update; BLI_rcti_init(&gpu_texture_region_to_update, floor((changed_overlapping_region_in_uv_space.xmin - info.uv_bounds.xmin) * @@ -275,8 +274,8 @@ template class ScreenSpaceDrawingMode : public AbstractD ceil((changed_overlapping_region_in_uv_space.ymin - tile_offset_y) * tile_height), ceil((changed_overlapping_region_in_uv_space.ymax - tile_offset_y) * tile_height)); - // Create an image buffer with a size - // extract and scale into an imbuf + /* Create an image buffer with a size. + * Extract and scale into an imbuf. */ const int texture_region_width = BLI_rcti_size_x(&gpu_texture_region_to_update); const int texture_region_height = BLI_rcti_size_y(&gpu_texture_region_to_update); @@ -437,17 +436,17 @@ template class ScreenSpaceDrawingMode : public AbstractD instance_data->partial_update.ensure_image(image); instance_data->clear_dirty_flag(); - // Step: Find out which screen space textures are needed to draw on the screen. Remove the - // screen space textures that aren't needed. + /* Step: Find out which screen space textures are needed to draw on the screen. Remove the + * screen space textures that aren't needed. */ const ARegion *region = draw_ctx->region; method.update_screen_space_bounds(region); method.update_uv_bounds(region); - // Step: Update the GPU textures based on the changes in the image. + /* Step: Update the GPU textures based on the changes in the image. */ instance_data->update_gpu_texture_allocations(); update_textures(*instance_data, image, iuser); - // Step: Add the GPU textures to the shgroup. + /* Step: Add the GPU textures to the shgroup. */ instance_data->update_batches(); add_depth_shgroups(*instance_data, image, iuser); add_shgroups(instance_data); diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index a24a3a5a3a7..4a8670a9ee2 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -999,7 +999,7 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); - // Build patch coordinates for all the face dots + /* Build patch coordinates for all the face dots. */ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), mesh_eval->totpoly); CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data( @@ -1760,7 +1760,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, int *mat_start = static_cast(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start")); int *subdiv_polygon_offset = cache->subdiv_polygon_offset; - // TODO: parallel_reduce? + /* TODO: parallel_reduce? */ for (int i = 0; i < mesh_eval->totpoly; i++) { const MPoly *mpoly = &mesh_eval->mpoly[i]; const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index afb786da8c6..c910162415d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4635,7 +4635,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) } } - /* Separate the entrie stroke. */ + /* Separate the entire stroke. */ if (all_points_selected) { /* deselect old stroke */ gps->flag &= ~GP_STROKE_SELECT; diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 90bbde4976c..3076058c075 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -51,7 +51,7 @@ typedef struct GPUSelectResult { /** * The nearest depth. * - Only supported by picking modes (#GPU_SELECT_PICK_ALL and #GPU_SELECT_PICK_NEAREST) - * since occlusion quiries don't provide a convenient way of accessing the depth-buffer. + * since occlusion quires don't provide a convenient way of accessing the depth-buffer. * - OpenGL's `GL_SELECT` supported both near and far depths, * this has not been included as Blender doesn't need this however support could be added. */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 6fae4a13918..7812c7a7257 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -272,7 +272,8 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl); * Fills the whole texture with the same data for all pixels. * \warning Only work for 2D texture for now. * \warning Only clears the mip 0 of the texture. - * \param data_format: data format of the pixel data. \note The format is float for unorm textures. + * \param data_format: data format of the pixel data. + * \note The format is float for unorm textures. * \param data: 1 pixel worth of data to fill the texture with. */ void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh index f1a8178bf0a..692eb7f5db5 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -125,10 +125,10 @@ constexpr bool is_type_integral = (... && std::is_integral_v>); template constexpr bool is_type_string_related = (... && std::is_constructible_v); -// gcc (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on, -// results in "obj_export_io.hh:205:18: warning: ā€˜%sā€™ directive output truncated writing 34 bytes -// into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered -// as an edge case by tests on purpose. +/* GCC (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on, + * results in "obj_export_io.hh:205:18: warning: ā€˜%sā€™ directive output truncated writing 34 bytes + * into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered + * as an edge case by tests on purpose. */ #if defined __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-truncation" diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index e79cbc838d4..e80c8559020 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -237,7 +237,7 @@ static void rna_AssetMetaData_catalog_id_set(PointerRNA *ptr, const char *value) } if (!BLI_uuid_parse_string(&new_uuid, value)) { - // TODO(Sybren): raise ValueError exception once that's possible from an RNA setter. + /* TODO(@sybren): raise ValueError exception once that's possible from an RNA setter. */ printf("UUID %s not formatted correctly, ignoring new value\n", value); return; } diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index d4de20b5328..0e0391197ea 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -369,9 +369,10 @@ void rna_ViewLayer_active_aov_index_range( PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax); int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr); void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value); -/** Set `r_rna_path` with the base viewlayer path. +/** + * Set `r_rna_path` with the base view-layer path. * `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`. - * \return actual length of the generayted RNA path. + * \return actual length of the generated RNA path. */ size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer, char *r_rna_path, diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 5a9d9db5367..b864aa64709 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -48,16 +48,17 @@ namespace blender::render::texturemargin { -/* The map class contains both a pixel map which maps out polygon indices for all UV-polygons and +/** + * The map class contains both a pixel map which maps out polygon indices for all UV-polygons and * adjacency tables. */ class TextureMarginMap { static const int directions[8][2]; static const int distances[8]; - /* Maps UV-edges to their corresponding UV-edge. */ + /** Maps UV-edges to their corresponding UV-edge. */ Vector loop_adjacency_map_; - /* Maps UV-edges to their corresponding polygon. */ + /** Maps UV-edges to their corresponding polygon. */ Vector loop_to_poly_map_; int w_, h_; @@ -132,9 +133,7 @@ class TextureMarginMap { static void zscan_store_pixel( void *map, int x, int y, [[maybe_unused]] float u, [[maybe_unused]] float v) { - /* NOTE: Not thread safe, see comment above. - * - */ + /* NOTE: Not thread safe, see comment above. */ TextureMarginMap *m = static_cast(map); m->set_pixel(x, y, m->value_to_store_); if (m->mask_) { @@ -153,7 +152,8 @@ class TextureMarginMap { #define IsDijkstraPixel(dp) ((dp)&0x80000000) #define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF) - /* Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map. + /** + * Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map. * For each pixel mark which direction is the shortest way to a polygon. */ void grow_dijkstra(int margin) @@ -188,8 +188,10 @@ class TextureMarginMap { } } - // std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); - // Not strictly needed because at this point it already is a heap. + /* Not strictly needed because at this point it already is a heap. */ +#if 0 + std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); +#endif while (active_pixels.size()) { std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); @@ -215,7 +217,8 @@ class TextureMarginMap { } } - /* Walk over the map and for margin pixels follow the direction stored in the bottom 3 + /** + * Walk over the map and for margin pixels follow the direction stored in the bottom 3 * bits back to the polygon. * Then look up the pixel from the next polygon. */ @@ -324,10 +327,12 @@ class TextureMarginMap { } } - /* Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well. - * Because the Dijkstra is not vey exact in determining which polygon is the closest, the + /** + * Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well. + * Because the Dijkstra is not very exact in determining which polygon is the closest, the * polygon we need can be the one next to the one the Dijkstra map provides. To prevent missing - * pixels also check the neighbouring polygons. */ + * pixels also check the neighboring polygons. + */ bool lookup_pixel_polygon_neighbourhood( float x, float y, uint32_t *r_start_poly, float *r_destx, float *r_desty, int *r_other_poly) { @@ -344,8 +349,8 @@ class TextureMarginMap { float mindist = -1.f; - /* Loop over all adjacent polyons and determine which edge is closest. - * This could be optimized by only inspecting neigbours which are on the edge of an island. + /* Loop over all adjacent polygons and determine which edge is closest. + * This could be optimized by only inspecting neighbors which are on the edge of an island. * But it seems fast enough for now and that would add a lot of complexity. */ for (int i = 0; i < totloop; i++) { int otherloop = loop_adjacency_map_[i + loopstart]; @@ -370,10 +375,12 @@ class TextureMarginMap { return mindist >= 0.f; } - /* Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon. + /** + * Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon. * Then return the location of the equivalent pixel in the other polygon. * Returns true if a new pixel location was found, false if it wasn't, which can happen if the - * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. */ + * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. + */ bool lookup_pixel(float x, float y, int src_poly, @@ -568,7 +575,9 @@ static void generate_margin(ImBuf *ibuf, vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f); } - BLI_assert(lt->poly < 0x80000000); // NOTE: we need the top bit for the dijkstra distance map + /* NOTE: we need the top bit for the dijkstra distance map. */ + BLI_assert(lt->poly < 0x80000000); + map.rasterize_tri(vec[0], vec[1], vec[2], lt->poly, draw_new_mask ? mask : nullptr); } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index be29dcfcd0c..dd8966acfd8 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -297,7 +297,7 @@ static void seq_add_sound_av_sync(Main *bmain, Scene *scene, Sequence *seq, SeqL const double av_stream_offset = sound_stream.start - load_data->r_video_stream_start; const int frame_offset = av_stream_offset * FPS; - /* Set subframe offset. */ + /* Set sub-frame offset. */ seq->sound->offset_time = ((double)frame_offset / FPS) - av_stream_offset; SEQ_transform_translate_sequence(scene, seq, frame_offset); } diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py index ebc35c1178c..705a026e441 100644 --- a/tests/python/bl_keymap_validate.py +++ b/tests/python/bl_keymap_validate.py @@ -162,7 +162,7 @@ def keymap_data_clean(keyconfig_data: typing.List, *, relaxed: bool) -> None: item_prop.pop("properties") # Needed so: `{"properties": ()}` matches `None` as there is no meaningful difference. - # Wruting `None` makes the most sense when explicitly written, however generated properties + # Writing `None` makes the most sense when explicitly written, however generated properties # might be empty and it's not worth adding checks in the generation logic to use `None` # just to satisfy this check. if not item_prop: -- cgit v1.2.3 From 9b779993f02811da681fe795651153abe737a501 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 13:35:43 +1100 Subject: Docs: add doc-string for RNA_property_is_set_ex use_ghost argument --- source/blender/makesrna/RNA_access.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a0d45ee4247..130402a31db 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -1514,10 +1514,21 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name); /** * Check if the #IDproperty exists, for operators. + * + * \param use_ghost: Internally an #IDProperty may exist, + * without the RNA considering it to be "set", see #IDP_FLAG_GHOST. + * This is used for operators, where executing an operator that has run previously + * will re-use the last value (unless #PROP_SKIP_SAVE property is set). + * In this case, the presence of the an existing value shouldn't prevent it being initialized + * from the context. Even though the this value will be returned if it's requested, + * it's not considered to be set (as it would if the menu item or key-map defined it's value). + * Set `use_ghost` to true for default behavior, otherwise false to check if there is a value + * exists internally and would be returned on request. */ bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost); bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop); +/** See #RNA_property_is_set_ex documentation. */ bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost); bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier); bool RNA_property_is_idprop(const PropertyRNA *prop); -- cgit v1.2.3 From 709f67cbf0be66cbf6f23a38c89e5cf62071d8a0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 17:28:48 +1100 Subject: Docs: note that Bone.xwidth & zwidth are doubled --- source/blender/makesdna/DNA_armature_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 566ffd19669..1005b5186aa 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -77,7 +77,7 @@ typedef struct Bone { /** dist, weight: for non-deformgroup deforms. */ float dist, weight; /** - * The width for block bones. + * The width for block bones. The final X/Z bone widths are double these values. * * \note keep in this order for transform code which stores a pointer to `xwidth`, * accessing length and `zwidth` as offsets. -- cgit v1.2.3 From cabc9506f9ace9f89f4a6d92dff676284e3a989f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 18:02:13 +1100 Subject: Fix crash in recent pose-bone transform cleanup ff5e8e6d535374891e09bc0e6ceb7059a22bdd53 dereferenced a NULL pointer when dragging a bone with a connected parent in pose-mode. --- .../editors/transform/transform_convert_armature.c | 34 ++++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 2a696dd0593..04a8d462924 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -751,28 +751,30 @@ void createTransPose(TransInfo *t) tc->data_len++; - if (has_translate_rotate[0] && has_translate_rotate[1]) { - continue; - } + if (has_translate_rotate != NULL) { + if (has_translate_rotate[0] && has_translate_rotate[1]) { + continue; + } - if (has_targetless_ik(pchan) == NULL) { - if (pchan->parent && (bone->flag & BONE_CONNECTED)) { - if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) { - has_translate_rotate[0] = true; + if (has_targetless_ik(pchan) == NULL) { + if (pchan->parent && (bone->flag & BONE_CONNECTED)) { + if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) { + has_translate_rotate[0] = true; + } } - } - else { - if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) { - has_translate_rotate[0] = true; + else { + if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) { + has_translate_rotate[0] = true; + } + } + if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) { + has_translate_rotate[1] = true; } } - if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) { - has_translate_rotate[1] = true; + else { + has_translate_rotate[0] = true; } } - else { - has_translate_rotate[0] = true; - } } if (tc->data_len == 0) { -- cgit v1.2.3 From da5e72eb01027d6992244983fc86b1d919c9c8bb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 18:06:51 +1100 Subject: Cleanup: exclude bone names & axes from selection drawing These aren't used for picking bones so there is no need to draw them. --- .../draw/engines/overlay/overlay_armature.c | 39 +++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 4029f1237e8..2b80ccc57d5 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -2084,7 +2084,9 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; - draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag); + if (!is_select) { + draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag); + } if (arm->drawtype == ARM_ENVELOPE) { draw_bone_update_disp_matrix_default(eBone, NULL); @@ -2107,12 +2109,14 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id); } - if (show_text && (arm->flag & ARM_DRAWNAMES)) { - draw_bone_name(ctx, eBone, NULL, arm, boneflag); - } + if (!is_select) { + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, eBone, NULL, arm, boneflag); + } - if (arm->flag & ARM_DRAWAXES) { - draw_axes(ctx, eBone, NULL, arm); + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, eBone, NULL, arm); + } } } } @@ -2221,7 +2225,9 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; } - draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); + if (!is_pose_select) { + draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); + } if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { draw_bone_update_disp_matrix_custom(pchan); @@ -2248,16 +2254,19 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id); } - if (draw_dofs) { - draw_bone_degrees_of_freedom(ctx, pchan); - } + /* These aren't included in the selection. */ + if (!is_pose_select) { + if (draw_dofs) { + draw_bone_degrees_of_freedom(ctx, pchan); + } - if (show_text && (arm->flag & ARM_DRAWNAMES)) { - draw_bone_name(ctx, NULL, pchan, arm, boneflag); - } + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, NULL, pchan, arm, boneflag); + } - if (arm->flag & ARM_DRAWAXES) { - draw_axes(ctx, NULL, pchan, arm); + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, NULL, pchan, arm); + } } } } -- cgit v1.2.3 From e8b3bd15e8d91c3cb8fa3bf33b3328e1dd109b75 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 18:10:27 +1100 Subject: Cleanup: skip redundant steps when the selection buffer is cached The viewport theme loaded and virtual modifiers allocated unnecessary. --- source/blender/editors/space_view3d/view3d_view.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 9a2cc76c44e..d6b928c6fa7 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -981,6 +981,15 @@ int view3d_opengl_select_ex(ViewContext *vc, } } + /* Re-use cache (rect must be smaller than the cached) + * other context is assumed to be unchanged */ + if (GPU_select_is_cached()) { + GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0); + GPU_select_cache_load_id(); + hits = GPU_select_end(); + goto finally; + } + /* Important to use 'vc->obact', not 'OBACT(vc->view_layer)' below, * so it will be NULL when hidden. */ struct { @@ -1040,15 +1049,6 @@ int view3d_opengl_select_ex(ViewContext *vc, UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); - /* Re-use cache (rect must be smaller than the cached) - * other context is assumed to be unchanged */ - if (GPU_select_is_cached()) { - GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0); - GPU_select_cache_load_id(); - hits = GPU_select_end(); - goto finally; - } - /* All of the queries need to be perform on the drawing context. */ DRW_opengl_context_enable(); @@ -1132,14 +1132,14 @@ int view3d_opengl_select_ex(ViewContext *vc, DRW_opengl_context_disable(); + UI_Theme_Restore(&theme_state); + finally: if (hits < 0) { printf("Too many objects in select buffer\n"); /* XXX make error message */ } - UI_Theme_Restore(&theme_state); - return hits; } -- cgit v1.2.3 From 49279196139fee58c38d4724856dfe06d9e6705f Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 2 Feb 2022 08:32:32 +0100 Subject: Cleanup: Use correct identifier for ShaderParameters. Code use struct and class, but should only have used struct. --- source/blender/draw/engines/image/image_space.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/image/image_space.hh b/source/blender/draw/engines/image/image_space.hh index 29d9cd4340b..fbb92ce24aa 100644 --- a/source/blender/draw/engines/image/image_space.hh +++ b/source/blender/draw/engines/image/image_space.hh @@ -22,7 +22,7 @@ #pragma once -class ShaderParameters; +struct ShaderParameters; /** * Space accessor. -- cgit v1.2.3 From 286fcb3a605a51a2d8e542095ffa87ceb71fdd08 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Feb 2022 16:11:59 +0100 Subject: LibOverride: Add 'owner library' info to some liboverride code. This will help when dealing with liboverrides from other library files, e.g for resync or proxies conversion. This commit only affects proxy conversion. Part of T91671. --- source/blender/blenkernel/BKE_lib_override.h | 12 +++++++ source/blender/blenkernel/intern/lib_override.c | 38 +++++++++++++++------- source/blender/editors/object/object_relations.c | 2 +- .../editors/space_outliner/outliner_tools.cc | 2 +- source/blender/makesrna/intern/rna_ID.c | 3 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 30e75259967..e8065566c97 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -100,6 +100,9 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, * main. You can add more local IDs to be remapped to use new overriding ones by setting their * LIB_TAG_DOIT tag. * + * \param owner_library: the library in which the overrides should be created. Besides versioning + * and resync code path, this should always be NULL (i.e. the local .blend file). + * * \param reference_library: the library from which the linked data being overridden come from * (i.e. the library of the linked reference ID). * @@ -109,6 +112,7 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, * \return \a true on success, \a false otherwise. */ bool BKE_lib_override_library_create_from_tag(struct Main *bmain, + struct Library *owner_library, const struct Library *reference_library, bool do_no_main); /** @@ -122,16 +126,24 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain, * * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in * which case \a scene's master collection children hierarchy is used instead). + * + * \param owner_library: the library in which the overrides should be created. Besides versioning + * and resync code path, this should always be NULL (i.e. the local .blend file). + * * \param id_root: The root ID to create an override from. + * * \param id_reference: Some reference ID used to do some post-processing after overrides have been * created, may be NULL. Typically, the Empty object instantiating the linked collection we * override, currently. + * * \param r_id_root_override: if not NULL, the override generated for the given \a id_root. + * * \return true if override was successfully created. */ bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, + struct Library *owner_library, struct ID *id_root, struct ID *id_reference, struct ID **r_id_root_override); diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d1375b1e5b5..a2c3cafc029 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -211,6 +211,7 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo } static ID *lib_override_library_create_from(Main *bmain, + Library *owner_library, ID *reference_id, const int lib_id_copy_flags) { @@ -227,6 +228,12 @@ static ID *lib_override_library_create_from(Main *bmain, } id_us_min(local_id); + /* TODO: Handle this properly in LIB_NO_MAIN case as well (i.e. resync case). Or offload to + * generic ID copy code? */ + if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) == 0) { + local_id->lib = owner_library; + } + BKE_lib_override_library_init(local_id, reference_id); /* NOTE: From liboverride perspective (and RNA one), shape keys are considered as local embedded @@ -281,7 +288,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, BLI_assert(reference_id != NULL); BLI_assert(ID_IS_LINKED(reference_id)); - ID *local_id = lib_override_library_create_from(bmain, reference_id, 0); + ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0); /* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant * mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies. * Ref T94650. */ @@ -320,6 +327,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, } bool BKE_lib_override_library_create_from_tag(Main *bmain, + Library *owner_library, const Library *reference_library, const bool do_no_main) { @@ -351,7 +359,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, * This requires extra care further down the resync process, * see: #BKE_lib_override_library_resync. */ reference_id->newid = lib_override_library_create_from( - bmain, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0); + bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0); if (reference_id->newid == NULL) { success = false; break; @@ -813,7 +821,10 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data) lib_override_overrides_group_tag_recursive(data); } -static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_root) +static bool lib_override_library_create_do(Main *bmain, + Scene *scene, + Library *owner_library, + ID *id_root) { BKE_main_relations_create(bmain, 0); LibOverrideGroupTagData data = {.bmain = bmain, @@ -832,12 +843,13 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo BKE_main_relations_free(bmain); lib_override_group_tag_data_clear(&data); - return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false); + return BKE_lib_override_library_create_from_tag(bmain, owner_library, id_root->lib, false); } static void lib_override_library_create_post_process(Main *bmain, Scene *scene, ViewLayer *view_layer, + const Library *owner_library, ID *id_root, ID *id_reference, Collection *residual_storage, @@ -859,7 +871,8 @@ static void lib_override_library_create_post_process(Main *bmain, /* Instantiating the root collection or object should never be needed in resync case, since the * old override would be remapped to the new one. */ - if (!is_resync && id_root != NULL && id_root->newid != NULL && !ID_IS_LINKED(id_root->newid)) { + if (!is_resync && id_root != NULL && id_root->newid != NULL && + (!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) { switch (GS(id_root->name)) { case ID_GR: { Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? @@ -904,7 +917,7 @@ static void lib_override_library_create_post_process(Main *bmain, Collection *default_instantiating_collection = residual_storage; LISTBASE_FOREACH (Object *, ob, &bmain->objects) { Object *ob_new = (Object *)ob->id.newid; - if (ob_new == NULL || ID_IS_LINKED(ob_new)) { + if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) { continue; } @@ -967,6 +980,7 @@ static void lib_override_library_create_post_process(Main *bmain, bool BKE_lib_override_library_create(Main *bmain, Scene *scene, ViewLayer *view_layer, + Library *owner_library, ID *id_root, ID *id_reference, ID **r_id_root_override) @@ -975,7 +989,7 @@ bool BKE_lib_override_library_create(Main *bmain, *r_id_root_override = NULL; } - const bool success = lib_override_library_create_do(bmain, scene, id_root); + const bool success = lib_override_library_create_do(bmain, scene, owner_library, id_root); if (!success) { return success; @@ -986,7 +1000,7 @@ bool BKE_lib_override_library_create(Main *bmain, } lib_override_library_create_post_process( - bmain, scene, view_layer, id_root, id_reference, NULL, false); + bmain, scene, view_layer, owner_library, id_root, id_reference, NULL, false); /* Cleanup. */ BKE_main_id_newptr_and_tag_clear(bmain); @@ -1055,7 +1069,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, } FOREACH_MAIN_ID_END; - return BKE_lib_override_library_create(bmain, scene, view_layer, id_root, id_reference, NULL); + return BKE_lib_override_library_create( + bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_reference, NULL); } static void lib_override_library_proxy_convert_do(Main *bmain, @@ -1288,7 +1303,7 @@ static bool lib_override_library_resync(Main *bmain, * override IDs (including within the old overrides themselves, since those are tagged too * above). */ const bool success = BKE_lib_override_library_create_from_tag( - bmain, id_root_reference->lib, true); + bmain, NULL, id_root_reference->lib, true); if (!success) { return success; @@ -1502,6 +1517,7 @@ static bool lib_override_library_resync(Main *bmain, lib_override_library_create_post_process(bmain, scene, view_layer, + NULL, id_root_reference, id_root, override_resync_residual_storage, @@ -1926,7 +1942,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, /* Essentially ensures that potentially new overrides of new objects will be instantiated. */ lib_override_library_create_post_process( - bmain, scene, view_layer, NULL, NULL, override_resync_residual_storage, true); + bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true); if (BKE_collection_is_empty(override_resync_residual_storage)) { BKE_collection_delete(bmain, override_resync_residual_storage, true); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a6eb35d49b9..ee594398f4a 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2334,7 +2334,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op) BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); const bool success = BKE_lib_override_library_create( - bmain, scene, view_layer, id_root, &obact->id, NULL); + bmain, scene, view_layer, NULL, id_root, &obact->id, NULL); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 03fc4c20fe5..02e8ab2f128 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -875,7 +875,7 @@ static void id_override_library_create_fn(bContext *C, } success = BKE_lib_override_library_create( - bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr); + bmain, CTX_data_scene(C), CTX_data_view_layer(C), NULL, id_root, id_reference, nullptr); } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) { success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 1ae036a254e..1f3dd34a0a7 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -719,7 +719,8 @@ static ID *rna_ID_override_hierarchy_create( BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); ID *id_root_override = NULL; - BKE_lib_override_library_create(bmain, scene, view_layer, id, id_reference, &id_root_override); + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, id_reference, &id_root_override); WM_main_add_notifier(NC_ID | NA_ADDED, NULL); WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); -- cgit v1.2.3 From 049df7ef943917fe1e86f84cc6213d319fa4c138 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Feb 2022 12:09:26 +0100 Subject: Proxies Removal: Handle conversion to liboverrides also for linked data. So far linked proxies were just kept as-is, this is no longer an option. Attempt to convert them into liboverrides as much as possible, though some cases won't be supported: - Appending proxies is broken since a long time, so conversion will fail here as well. - When linking data, some cases will fail to convert properly. in particular, if the linked proxy object is not instanced in a scene (e.g. when linking a collection containing a proxy as an epty-instanced collection instead of a view-layer-instanced collection). NOTE: converion when linking/appending is done unconditionnaly, option to not convert on file load will be removed in next commit anyway. Part of T91671. --- .../blenkernel/intern/blendfile_link_append.c | 24 ++++++++++++++ source/blender/blenkernel/intern/lib_override.c | 37 ++++++++++++++-------- source/blender/blenloader/BLO_readfile.h | 2 -- source/blender/windowmanager/intern/wm_files.c | 20 ++++++------ 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 9b3f4c2fae8..4149821b67b 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -993,6 +993,24 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d /** \name Library link/append code. * \{ */ +static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports) +{ + BlendFileReadReport bf_reports = {.reports = reports}; + BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports); + + if (bf_reports.count.proxies_to_lib_overrides_success != 0 || + bf_reports.count.proxies_to_lib_overrides_failures != 0) { + BKE_reportf( + bf_reports.reports, + RPT_WARNING, + "Proxies have been removed from Blender (%d proxies were automatically converted " + "to library overrides, %d proxies could not be converted and were cleared). " + "Please consider re-saving any library .blend file with the newest Blender version.", + bf_reports.count.proxies_to_lib_overrides_success, + bf_reports.count.proxies_to_lib_overrides_failures); + } +} + void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) { if (lapp_context->num_items == 0) { @@ -1259,6 +1277,8 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList * } BKE_main_id_newptr_and_tag_clear(bmain); + + blendfile_link_append_proxies_convert(bmain, reports); } void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) @@ -1361,6 +1381,10 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re .active_collection = NULL}; loose_data_instantiate(&instantiate_context); } + + if ((lapp_context->params->flag & FILE_LINK) != 0) { + blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports); + } } /** \} */ diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index a2c3cafc029..5abe0f5e6be 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1040,7 +1040,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not * sure this is a valid state, but for now just abort the overriding process. */ - if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) { + if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root)) { + if (ob_proxy->proxy != NULL) { + ob_proxy->proxy->proxy_from = NULL; + } + id_us_min((ID *)ob_proxy->proxy); + ob_proxy->proxy = ob_proxy->proxy_group = NULL; return false; } @@ -1058,12 +1063,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE); /* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created - * overrides. + * overrides. Also do that for the IDs from the same lib as the proxy in case it is linked. * While this might not be 100% the desired behavior, it is likely to be the case most of the * time. Ref: T91711. */ ID *id_iter; FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - if (!ID_IS_LINKED(id_iter)) { + if (!ID_IS_LINKED(id_iter) || id_iter->lib == ob_proxy->id.lib) { id_iter->tag |= LIB_TAG_DOIT; } } @@ -1120,18 +1125,24 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor } LISTBASE_FOREACH (Object *, object, &bmain->objects) { - if (ID_IS_LINKED(object)) { - if (object->proxy != NULL) { - CLOG_WARN(&LOG, "Did not try to convert linked proxy object '%s'", object->id.name); - reports->count.linked_proxies++; - } - continue; - } - if (object->proxy_group != NULL || object->proxy != NULL) { - CLOG_WARN( - &LOG, "Proxy object '%s' failed to be converted to library override", object->id.name); + if (ID_IS_LINKED(object)) { + CLOG_WARN(&LOG, + "Linked proxy object '%s' from '%s' failed to be converted to library override", + object->id.name + 2, + object->id.lib->filepath); + } + else { + CLOG_WARN(&LOG, + "Proxy object '%s' failed to be converted to library override", + object->id.name + 2); + } reports->count.proxies_to_lib_overrides_failures++; + if (object->proxy != NULL) { + object->proxy->proxy_from = NULL; + } + id_us_min((ID *)object->proxy); + object->proxy = object->proxy_group = NULL; } } } diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index c4c3b42cb63..066b180dcc9 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -117,8 +117,6 @@ typedef struct BlendFileReadReport { /* Number of root override IDs that were resynced. */ int resynced_lib_overrides; - /* Number of (non-converted) linked proxies. */ - int linked_proxies; /* Number of proxies converted to library overrides. */ int proxies_to_lib_overrides_success; /* Number of proxies that failed to convert to library overrides. */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 1478712c3cd..723c572c4da 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -874,18 +874,16 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports) duration_lib_override_recursive_resync_seconds); } - if (bf_reports->count.linked_proxies != 0 || - bf_reports->count.proxies_to_lib_overrides_success != 0 || + if (bf_reports->count.proxies_to_lib_overrides_success != 0 || bf_reports->count.proxies_to_lib_overrides_failures != 0) { - BKE_reportf(bf_reports->reports, - RPT_WARNING, - "Proxies are deprecated (%d proxies were automatically converted to library " - "overrides, %d proxies could not be converted and %d linked proxies were kept " - "untouched). If you need to keep proxies for the time being, please disable the " - "`Proxy to Override Auto Conversion` in Experimental user preferences", - bf_reports->count.proxies_to_lib_overrides_success, - bf_reports->count.proxies_to_lib_overrides_failures, - bf_reports->count.linked_proxies); + BKE_reportf( + bf_reports->reports, + RPT_WARNING, + "Proxies have been removed from Blender (%d proxies were automatically converted " + "to library overrides, %d proxies could not be converted and were cleared). " + "Please also consider re-saving any library .blend file with the newest Blender version.", + bf_reports->count.proxies_to_lib_overrides_success, + bf_reports->count.proxies_to_lib_overrides_failures); } if (bf_reports->count.sequence_strips_skipped != 0) { -- cgit v1.2.3 From 829d93ff069c02d205cfc9e294efa9d2210e1ff8 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Feb 2022 16:51:53 +0100 Subject: Remove option to not auto-convert proxies on file load. Now all proxies will always be converted to library overrides. If conversion fails, they are simply 'disabled'. This should be the last 'user-visible' step of proxies removal. Remaining upcoming commits will remove internal ID management, depsgraph and evaluation code related to proxies. Also bump the blendfile subversion. Part of T91671. --- release/scripts/startup/bl_ui/space_userpref.py | 1 - source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/blendfile.c | 26 ++++++++++++++++++---- .../blenkernel/intern/blendfile_link_append.c | 3 +++ source/blender/makesdna/DNA_userdef_types.h | 3 +-- source/blender/makesrna/intern/rna_userdef.c | 7 ------ 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 0548486c786..78ef68e0bab 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2316,7 +2316,6 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): context, ( ({"property": "use_undo_legacy"}, "T60695"), ({"property": "override_auto_resync"}, "T83811"), - ({"property": "proxy_to_override_auto_conversion"}, "T91671"), ({"property": "use_cycles_debug"}, None), ({"property": "use_geometry_nodes_legacy"}, "T91274"), ({"property": "show_asset_debug_info"}, None), diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 091f9784697..645d049fe71 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 0 +#define BLENDER_FILE_SUBVERSION 1 /* 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/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 6ae19c8036f..819f786a2d0 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -78,6 +78,23 @@ /** \name High Level `.blend` file read/write. * \{ */ +static bool blendfile_or_libraries_versions_atleast(Main *bmain, + const short versionfile, + const short subversionfile) +{ + if (!MAIN_VERSION_ATLEAST(bmain, versionfile, subversionfile)) { + return false; + } + + LISTBASE_FOREACH (Library *, library, &bmain->libraries) { + if (!MAIN_VERSION_ATLEAST(library, versionfile, subversionfile)) { + return false; + } + } + + return true; +} + static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data), char *path_dst, const char *path_src) @@ -349,10 +366,11 @@ static void setup_app_data(bContext *C, do_versions_ipos_to_animato(bmain); } - /* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */ - /* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a - * version bump and check here. */ - if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) { + /* NOTE: readfile's `do_version` does not allow to create new IDs, and only operates on a single + * library at a time. This code needs to operate on the whole Main at once. */ + /* NOTE: Check bmain version (i.e. current blend file version), AND the versions of all the + * linked libraries. */ + if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) { BKE_lib_override_library_main_proxy_convert(bmain, reports); } diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 4149821b67b..94d14b63437 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -995,6 +995,9 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports) { + /* NOTE: Do not bother checking file versions here, if there are no proxies to convert this code + * is quite fast anyway. */ + BlendFileReadReport bf_reports = {.reports = reports}; BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 15bb1ef920d..637dd216935 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -651,7 +651,6 @@ typedef struct UserDef_Experimental { /* Debug options, always available. */ char use_undo_legacy; char no_override_auto_resync; - char no_proxy_to_override_conversion; char use_cycles_debug; char use_geometry_nodes_legacy; char show_asset_debug_info; @@ -666,7 +665,7 @@ typedef struct UserDef_Experimental { char use_sculpt_tools_tilt; char use_extended_asset_browser; char use_override_templates; - char _pad[1]; + char _pad[2]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4379b4ebe1d..aef219c4236 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6386,13 +6386,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Enable library overrides automatic resync detection and process on file load. Disable when " "dealing with older .blend files that need manual Resync (Enforce) handling"); - prop = RNA_def_property(srna, "proxy_to_override_auto_conversion", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "no_proxy_to_override_conversion", 1); - RNA_def_property_ui_text( - prop, - "Proxy to Override Auto Conversion", - "Enable automatic conversion of proxies to library overrides on file load"); - prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1); RNA_def_property_ui_text( -- cgit v1.2.3 From 71b451bb628f47b8fe103fe151330030195bd498 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Feb 2022 10:35:32 +0100 Subject: Fix T95288: Shrinkwrap selection broken in edit mode Mistake in the 974981a63704: f the edit data is not present then the origindex codepath is to be used. Added a brief note about it on the top of the file. More ideally would be to remove edit mesh from non-bmesh-wrappers but this would require changes in the draw manager to make a proper decision about drawing edit mode overlays. --- source/blender/blenkernel/intern/mesh_iterators.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c index ff2ac8ecee9..3f2d81b6dc2 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -34,19 +34,29 @@ #include "MEM_guardedalloc.h" +/* General note on iterating vers/loops/edges/polys and end mode. + * + * The edit mesh pointer is set for both final and cage meshes in both cases when there are + * modifiers applied and not. This helps consistency of checks in the draw manager, where the + * existence of the edit mesh pointer does not depend on object configuration. + * + * For the iterating, however, we need to follow the `CD_ORIGINDEX` code paths when there are + * modifiers applied on the cage. In the code terms it means that the check for the edit mode code + * path needs to consist of both edit mesh and edit data checks. */ + void BKE_mesh_foreach_mapped_vert( Mesh *mesh, void (*func)(void *userData, int index, const float co[3], const float no[3]), void *userData, MeshForeachFlag flag) { - if (mesh->edit_mesh != NULL) { + if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMVert *eve; int i; - if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) { + if (mesh->runtime.edit_data->vertexCos != NULL) { const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; const float(*vertexNos)[3]; if (flag & MESH_FOREACH_USE_NORMAL) { @@ -100,13 +110,13 @@ void BKE_mesh_foreach_mapped_edge( void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { - if (mesh->edit_mesh != NULL) { + if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMEdge *eed; int i; - if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) { + if (mesh->runtime.edit_data->vertexCos != NULL) { const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; BM_mesh_elem_index_ensure(bm, BM_VERT); @@ -158,14 +168,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, /* We can't use dm->getLoopDataLayout(dm) here, * we want to always access dm->loopData, EditDerivedBMesh would * return loop data from bmesh itself. */ - if (mesh->edit_mesh != NULL) { + if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMFace *efa; - const float(*vertexCos)[3] = mesh->runtime.edit_data ? mesh->runtime.edit_data->vertexCos : - NULL; + const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; /* XXX: investigate using EditMesh data. */ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? -- cgit v1.2.3 From a985f558a6eb16cd6f00b550712b86923ab33fd3 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 2 Feb 2022 10:54:54 +0100 Subject: Fix T95084: evaluate all output attributes before changing geometry This refactors how output attributes are computed in the geometry nodes modifier. Previously, all output attributes were computed one after the other. Every attribute was stored on the geometry directly after computing it. The issue was that other output attributes might depend on the already overwritten attributes, leading to unexpected behavior. The solution is to compute all output attributes first before changing the geometry. Under specific circumstances, this refactor can result in a speedup, because output attributes on the same domain are evaluated together now. Overwriting existing might have become a bit slower, because we write the attribute into new buffer instead of using the existing one. Differential Revision: https://developer.blender.org/D13983 --- source/blender/modifiers/intern/MOD_nodes.cc | 203 ++++++++++++++++++--------- 1 file changed, 136 insertions(+), 67 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 49528845197..625d31b3548 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -109,6 +109,8 @@ using blender::float3; using blender::FunctionRef; using blender::IndexRange; using blender::Map; +using blender::MultiValueMap; +using blender::MutableSpan; using blender::Set; using blender::Span; using blender::StringRef; @@ -119,7 +121,9 @@ using blender::fn::Field; using blender::fn::GField; using blender::fn::GMutablePointer; using blender::fn::GPointer; +using blender::fn::GVArray; using blender::fn::ValueOrField; +using blender::fn::ValueOrFieldCPPType; using blender::nodes::FieldInferencingInterface; using blender::nodes::GeoNodeExecParams; using blender::nodes::InputSocketFieldType; @@ -892,80 +896,145 @@ static void clear_runtime_data(NodesModifierData *nmd) } } -static void store_field_on_geometry_component(GeometryComponent &component, - const StringRef attribute_name, - AttributeDomain domain, - const GField &field) +struct OutputAttributeInfo { + GField field; + StringRefNull name; +}; + +struct OutputAttributeToStore { + GeometryComponentType component_type; + AttributeDomain domain; + StringRefNull name; + GMutableSpan data; +}; + +/** + * The output attributes are organized based on their domain, because attributes on the same domain + * can be evaluated together. + */ +static MultiValueMap find_output_attributes_to_store( + const NodesModifierData &nmd, const NodeRef &output_node, Span output_values) { - /* If the attribute name corresponds to a built-in attribute, use the domain of the built-in - * attribute instead. */ - if (component.attribute_is_builtin(attribute_name)) { - component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); - std::optional meta_data = component.attribute_get_meta_data(attribute_name); - if (meta_data.has_value()) { - domain = meta_data->domain; + MultiValueMap outputs_by_domain; + for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { + if (!socket_type_has_attribute_toggle(*socket->bsocket())) { + continue; } - else { - return; + + const std::string prop_name = socket->identifier() + attribute_name_suffix; + const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str()); + if (prop == nullptr) { + continue; } + const StringRefNull attribute_name = IDP_String(prop); + if (attribute_name.is_empty()) { + continue; + } + + const int index = socket->index(); + const GPointer value = output_values[index]; + const ValueOrFieldCPPType *cpp_type = dynamic_cast(value.type()); + BLI_assert(cpp_type != nullptr); + const GField field = cpp_type->as_field(value.get()); + + const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink( + &nmd.node_group->outputs, socket->index()); + const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; + OutputAttributeInfo output_info; + output_info.field = std::move(field); + output_info.name = attribute_name; + outputs_by_domain.add(domain, std::move(output_info)); } - const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(field.cpp_type()); - OutputAttribute attribute = component.attribute_try_get_for_output_only( - attribute_name, domain, data_type); - if (attribute) { - /* In the future we could also evaluate all output fields at once. */ - const int domain_size = component.attribute_domain_size(domain); - blender::bke::GeometryComponentFieldContext field_context{component, domain}; - blender::fn::FieldEvaluator field_evaluator{field_context, domain_size}; - field_evaluator.add_with_destination(field, attribute.varray()); - field_evaluator.evaluate(); - attribute.save(); - } + return outputs_by_domain; } -static void store_output_value_in_geometry(GeometrySet &geometry_set, - NodesModifierData *nmd, - const InputSocketRef &socket, - const GPointer value) +/** + * The computed values are stored in newly allocated arrays. They still have to be moved to the + * actual geometry. + */ +static Vector compute_attributes_to_store( + const GeometrySet &geometry, + const MultiValueMap &outputs_by_domain) { - if (!socket_type_has_attribute_toggle(*socket.bsocket())) { - return; - } - const std::string prop_name = socket.identifier() + attribute_name_suffix; - const IDProperty *prop = IDP_GetPropertyFromGroup(nmd->settings.properties, prop_name.c_str()); - if (prop == nullptr) { - return; - } - const StringRefNull attribute_name = IDP_String(prop); - if (attribute_name.is_empty()) { - return; + Vector attributes_to_store; + for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}) { + if (!geometry.has(component_type)) { + continue; + } + const GeometryComponent &component = *geometry.get_component_for_read(component_type); + for (const auto item : outputs_by_domain.items()) { + const AttributeDomain domain = item.key; + const Span outputs_info = item.value; + if (!component.attribute_domain_supported(domain)) { + continue; + } + const int domain_size = component.attribute_domain_size(domain); + blender::bke::GeometryComponentFieldContext field_context{component, domain}; + blender::fn::FieldEvaluator field_evaluator{field_context, domain_size}; + for (const OutputAttributeInfo &output_info : outputs_info) { + const CPPType &type = output_info.field.cpp_type(); + OutputAttributeToStore store{ + component_type, + domain, + output_info.name, + GMutableSpan{ + type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}}; + field_evaluator.add_with_destination(output_info.field, store.data); + attributes_to_store.append(store); + } + field_evaluator.evaluate(); + } } - const blender::fn::ValueOrFieldCPPType *cpp_type = - dynamic_cast(value.type()); - BLI_assert(cpp_type != nullptr); + return attributes_to_store; +} - const GField field = cpp_type->as_field(value.get()); - const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs, - socket.index()); - const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; - if (geometry_set.has_mesh()) { - MeshComponent &component = geometry_set.get_component_for_write(); - store_field_on_geometry_component(component, attribute_name, domain, field); - } - if (geometry_set.has_pointcloud()) { - PointCloudComponent &component = geometry_set.get_component_for_write(); - store_field_on_geometry_component(component, attribute_name, domain, field); - } - if (geometry_set.has_curve()) { - CurveComponent &component = geometry_set.get_component_for_write(); - store_field_on_geometry_component(component, attribute_name, domain, field); - } - if (geometry_set.has_instances()) { - InstancesComponent &component = geometry_set.get_component_for_write(); - store_field_on_geometry_component(component, attribute_name, domain, field); +static void store_computed_output_attributes( + GeometrySet &geometry, const Span attributes_to_store) +{ + for (const OutputAttributeToStore &store : attributes_to_store) { + GeometryComponent &component = geometry.get_component_for_write(store.component_type); + /* Try deleting an existing attribute, so that we can just use `attribute_try_create` to pass + * in the data directly. */ + component.attribute_try_delete(store.name); + if (component.attribute_exists(store.name)) { + /* Copy the data into an existing attribute. */ + blender::bke::WriteAttributeLookup write_attribute = component.attribute_try_get_for_write( + store.name); + if (write_attribute) { + write_attribute.varray.set_all(store.data.data()); + store.data.type().destruct_n(store.data.data(), store.data.size()); + MEM_freeN(store.data.data()); + if (write_attribute.tag_modified_fn) { + write_attribute.tag_modified_fn(); + } + } + } + else { + component.attribute_try_create(store.name, + store.domain, + blender::bke::cpp_type_to_custom_data_type(store.data.type()), + AttributeInitMove(store.data.data())); + } } } +static void store_output_attributes(GeometrySet &geometry, + const NodesModifierData &nmd, + const NodeRef &output_node, + Span output_values) +{ + /* All new attribute values have to be computed before the geometry is actually changed. This is + * necessary because some fields might depend on attributes that are overwritten. */ + MultiValueMap outputs_by_domain = + find_output_attributes_to_store(nmd, output_node, output_values); + Vector attributes_to_store = compute_attributes_to_store( + geometry, outputs_by_domain); + store_computed_output_attributes(geometry, attributes_to_store); +} + /** * Evaluate a node group to compute the output geometry. */ @@ -1040,7 +1109,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr; blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params); - GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out(); + GeometrySet output_geometry_set = std::move(*eval_params.r_output_values[0].get()); if (geo_logger.has_value()) { geo_logger->log_output_geometry(output_geometry_set); @@ -1049,10 +1118,10 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger); } - for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { - GMutablePointer socket_value = eval_params.r_output_values[socket->index()]; - store_output_value_in_geometry(output_geometry_set, nmd, *socket, socket_value); - socket_value.destruct(); + store_output_attributes(output_geometry_set, *nmd, output_node, eval_params.r_output_values); + + for (GMutablePointer value : eval_params.r_output_values) { + value.destruct(); } return output_geometry_set; -- cgit v1.2.3 From 4dcaac6d33026759faad186542b6cfae0d87e4e9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 2 Feb 2022 21:05:16 +1100 Subject: Cleanup: comment printing when loading XML This printed text when the theme was changes from the quick setup. Also use a context manager for opening a file. --- release/scripts/modules/rna_xml.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py index 7f7b273c42b..aa8841c5efe 100644 --- a/release/scripts/modules/rna_xml.py +++ b/release/scripts/modules/rna_xml.py @@ -298,7 +298,7 @@ def xml2rna( del value_xml_split tp_name = 'ARRAY' -# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type)) + # print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type)) try: setattr(value, attr, value_xml_coerce) except ValueError: @@ -340,7 +340,6 @@ def xml2rna( else: # print(elems) - if len(elems) == 1: # sub node named by its type child_xml_real, = elems @@ -376,7 +375,6 @@ def _get_context_val(context, path): def xml_file_run(context, filepath, rna_map): - import xml.dom.minidom xml_nodes = xml.dom.minidom.parse(filepath) @@ -391,27 +389,25 @@ def xml_file_run(context, filepath, rna_map): value = _get_context_val(context, rna_path) if value is not Ellipsis and value is not None: - print(" loading XML: %r -> %r" % (filepath, rna_path)) + # print(" loading XML: %r -> %r" % (filepath, rna_path)) xml2rna(xml_node, root_rna=value) def xml_file_write(context, filepath, rna_map, *, skip_typemap=None): - - file = open(filepath, "w", encoding="utf-8") - fw = file.write - - fw("\n") - - for rna_path, _xml_tag in rna_map: - # xml_tag is ignored, we get this from the rna - value = _get_context_val(context, rna_path) - rna2xml(fw, + with open(filepath, "w", encoding="utf-8") as file: + fw = file.write + fw("\n") + + for rna_path, _xml_tag in rna_map: + # xml_tag is ignored, we get this from the rna + value = _get_context_val(context, rna_path) + rna2xml( + fw=fw, root_rna=value, method='ATTR', root_ident=" ", ident_val=" ", skip_typemap=skip_typemap, - ) + ) - fw("\n") - file.close() + fw("\n") -- cgit v1.2.3 From bf8597febe2020e654020ad60e8af35c635c1a9a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 2 Feb 2022 13:11:33 +0100 Subject: BLI: fix memory leak in VectorSet The leak happened when the vector set had to grow when it was empty but it had allocated the keys array already. --- source/blender/blenlib/BLI_vector_set.hh | 4 ++++ source/blender/blenlib/tests/BLI_vector_set_test.cc | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index 0aac96f93bc..ed744d09314 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -570,6 +570,10 @@ class VectorSet { if (this->size() == 0) { try { slots_.reinitialize(total_slots); + if (keys_ != nullptr) { + this->deallocate_keys_array(keys_); + keys_ = nullptr; + } keys_ = this->allocate_keys_array(usable_slots); } catch (...) { diff --git a/source/blender/blenlib/tests/BLI_vector_set_test.cc b/source/blender/blenlib/tests/BLI_vector_set_test.cc index c4016ca75e1..fe3130a846f 100644 --- a/source/blender/blenlib/tests/BLI_vector_set_test.cc +++ b/source/blender/blenlib/tests/BLI_vector_set_test.cc @@ -271,4 +271,14 @@ TEST(vector_set, LookupKey) EXPECT_EQ(set.lookup_key_ptr("a"), set.lookup_key_ptr_as("a")); } +TEST(vector_set, GrowWhenEmpty) +{ + /* Tests that the internal keys array is freed correctly when growing an empty set. */ + VectorSet set; + set.add(4); + set.remove(4); + EXPECT_TRUE(set.is_empty()); + set.reserve(100); +} + } // namespace blender::tests -- cgit v1.2.3