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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/armature/pose_transform.c4
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc2
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/include/ED_node.h28
-rw-r--r--source/blender/editors/include/ED_uvedit.h25
-rw-r--r--source/blender/editors/include/UI_interface.h4
-rw-r--r--source/blender/editors/include/UI_interface.hh1
-rw-r--r--source/blender/editors/include/UI_interface_icons.h12
-rw-r--r--source/blender/editors/include/UI_view2d.h2
-rw-r--r--source/blender/editors/interface/interface.cc5
-rw-r--r--source/blender/editors/interface/interface_context_path.cc14
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc2
-rw-r--r--source/blender/editors/interface/interface_icons.c121
-rw-r--r--source/blender/editors/interface/interface_intern.h4
-rw-r--r--source/blender/editors/interface/interface_layout.c4
-rw-r--r--source/blender/editors/interface/interface_ops.cc4
-rw-r--r--source/blender/editors/interface/interface_panel.cc6
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.cc2
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.cc41
-rw-r--r--source/blender/editors/interface/interface_region_popup.cc25
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c15
-rw-r--r--source/blender/editors/io/io_alembic.c2
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_gpencil_import.c2
-rw-r--r--source/blender/editors/io/io_obj.c40
-rw-r--r--source/blender/editors/io/io_stl_ops.c4
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c225
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c9
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.cc6
-rw-r--r--source/blender/editors/mesh/editmesh_undo.cc13
-rw-r--r--source/blender/editors/mesh/mesh_intern.h3
-rw-r--r--source/blender/editors/mesh/meshtools.cc2
-rw-r--r--source/blender/editors/object/object_add.cc197
-rw-r--r--source/blender/editors/object/object_modifier.cc42
-rw-r--r--source/blender/editors/object/object_relations.c29
-rw-r--r--source/blender/editors/object/object_vgroup.cc108
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c4
-rw-r--r--source/blender/editors/physics/particle_edit.c6
-rw-r--r--source/blender/editors/physics/particle_object.c9
-rw-r--r--source/blender/editors/physics/physics_fluid.c16
-rw-r--r--source/blender/editors/render/render_preview.cc2
-rw-r--r--source/blender/editors/render/render_shading.cc2
-rw-r--r--source/blender/editors/scene/scene_edit.c1
-rw-r--r--source/blender/editors/screen/area.c3
-rw-r--r--source/blender/editors/screen/workspace_edit.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c40
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.cc142
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_init.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c21
-rw-r--r--source/blender/editors/space_clip/clip_ops.c14
-rw-r--r--source/blender/editors/space_file/file_draw.c71
-rw-r--r--source/blender/editors/space_file/file_ops.c17
-rw-r--r--source/blender/editors/space_file/filelist.cc43
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/fsmenu.c26
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_image/image_draw.c28
-rw-r--r--source/blender/editors/space_image/image_ops.c8
-rw-r--r--source/blender/editors/space_image/image_sequence.c4
-rw-r--r--source/blender/editors/space_image/space_image.c3
-rw-r--r--source/blender/editors/space_info/info_stats.cc5
-rw-r--r--source/blender/editors/space_info/textview.c3
-rw-r--r--source/blender/editors/space_nla/nla_edit.c17
-rw-r--r--source/blender/editors/space_node/add_node_search.cc3
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc5
-rw-r--r--source/blender/editors/space_node/node_edit.cc43
-rw-r--r--source/blender/editors/space_node/node_intern.hh2
-rw-r--r--source/blender/editors/space_node/node_ops.cc12
-rw-r--r--source/blender/editors/space_node/node_relationships.cc332
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc88
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc80
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc13
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc16
-rw-r--r--source/blender/editors/space_view3d/drawobject.c5
-rw-r--r--source/blender/editors/space_view3d/space_view3d.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc6
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.cc8
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_ndof.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c98
-rw-r--r--source/blender/editors/transform/transform.h16
-rw-r--r--source/blender/editors/transform/transform_constraints.c15
-rw-r--r--source/blender/editors/transform/transform_convert.h12
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c2
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c43
-rw-r--r--source/blender/editors/transform/transform_convert_node.cc (renamed from source/blender/editors/transform/transform_convert_node.c)81
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c22
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c103
-rw-r--r--source/blender/editors/transform/transform_ops.c23
-rw-r--r--source/blender/editors/transform/transform_snap.c131
-rw-r--r--source/blender/editors/transform/transform_snap.h11
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc28
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/ed_viewer_path.cc3
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.cc290
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c158
125 files changed, 1967 insertions, 1356 deletions
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 2a23615caa3..9ed963f0c66 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -788,7 +788,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
* existing on its own.
*/
BKE_copybuffer_copy_tag_ID(&ob_copy.id);
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
BKE_copybuffer_copy_end(temp_bmain, str, op->reports);
/* We clear the lists so no datablocks gets freed,
* This is required because objects in temp bmain shares same pointers
@@ -844,7 +844,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
Main *tmp_bmain = BKE_main_new();
STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global());
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
BKE_main_free(tmp_bmain);
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index b0ff5c86520..7fdb924d769 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -488,7 +488,7 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
const char *asset_relpath = asset_handle.file_data->relpath;
char path[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(path, sizeof(path), library_path, asset_relpath);
+ BLI_path_join(path, sizeof(path), library_path, asset_relpath);
return path;
}
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index 08259090e0c..d1c46a8259f 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -860,7 +860,7 @@ static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op)
}
char file_path[PATH_MAX];
- BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename);
+ BLI_path_join(file_path, sizeof(file_path), lib->path, blend_filename);
RNA_string_set(op->ptr, "filepath", file_path);
return true;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 677bf1bb392..2fd58a9cee0 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -13,9 +13,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 340288b2d74..c6d7eb294fb 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -623,6 +623,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
true,
"Only Active",
"Copy only active Layer, uncheck to append all layers");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -3686,6 +3687,7 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
true,
"Only Active",
"Append only active material, uncheck to append all materials");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index c30b8c5ec6a..24e14fdce72 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -87,17 +87,6 @@ void ED_node_tag_update_id(struct ID *id);
float ED_node_grid_size(void);
-/* node_relationships.cc */
-
-/**
- * Test == 0, clear all intersect flags.
- */
-void ED_node_link_intersect_test(struct ScrArea *area, int test);
-/**
- * Assumes link with #NODE_LINKFLAG_HILITE set.
- */
-void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
-
/* node_edit.cc */
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
@@ -186,3 +175,20 @@ bool ED_space_node_color_sample(struct Main *bmain,
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+/* node_relationships.cc */
+
+namespace blender::ed::space_node {
+
+void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region);
+/**
+ * Assumes link with #NODE_LINKFLAG_HILITE set.
+ */
+void node_insert_on_link_flags(Main &bmain, SpaceNode &snode);
+void node_insert_on_link_flags_clear(bNodeTree &node_tree);
+
+} // namespace blender::ed::space_node
+
+#endif \ No newline at end of file
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index b499ae0ce59..b97cd6a9099 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -339,12 +339,22 @@ bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima,
bool use_active,
struct UVMapUDIM_Params *udim_params);
+typedef enum {
+ ED_UVPACK_MARGIN_SCALED = 0, /* Use scale of existing UVs to multiply margin. */
+ ED_UVPACK_MARGIN_ADD, /* Just add the margin, ignoring any UV scale. */
+ ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */
+} eUVPackIsland_MarginMethod;
+
+/** See also #UnwrapOptions. */
struct UVPackIsland_Params {
uint rotate : 1;
uint only_selected_uvs : 1;
uint only_selected_faces : 1;
uint use_seams : 1;
uint correct_aspect : 1;
+ bool ignore_pinned; /* Ignore islands which have any pinned UVs. */
+ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */
+ float margin; /* Additional space to add around each island. */
};
/**
@@ -353,9 +363,24 @@ struct UVPackIsland_Params {
bool uv_coords_isect_udim(const struct Image *image,
const int udim_grid[2],
const float coords[2]);
+
+/**
+ * Pack UV islands from multiple objects.
+ *
+ * \param scene: Scene containing the objects to be packed.
+ * \param objects: Array of Objects to pack.
+ * \param objects_len: Length of `objects` array.
+ * \param bmesh_override: BMesh array aligned with `objects`.
+ * Optional, when non-null this overrides object's BMesh.
+ * This is needed to perform UV packing on objects that aren't in edit-mode.
+ * \param udim_params: Parameters to specify UDIM target and UDIM source image.
+ * \param params: Parameters and options to pass to the packing engine.
+ *
+ */
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
Object **objects,
uint objects_len,
+ struct BMesh **bmesh_override,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 2a1941f0d9e..7e9422ff867 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1683,6 +1683,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name);
* Adds a hint to the button which draws right aligned, grayed out and never clipped.
*/
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
+void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
@@ -2788,7 +2789,8 @@ typedef struct uiPropertySplitWrapper {
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
-void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
+struct uiBut *uiItemL_ex(
+ uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
/**
* Helper to add a label and creates a property split layout if needed.
*/
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 6c756984203..fc03b0218c0 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -35,6 +35,7 @@ struct ContextPathItem {
std::string name;
/* #BIFIconID */
int icon;
+ int icon_indicator_number;
};
void context_path_add_generic(Vector<ContextPathItem> &path,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index a1a98a4b08c..9669e242dac 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -27,6 +27,12 @@ typedef struct IconFile {
int index;
} IconFile;
+typedef struct IconTextOverlay {
+ char text[5];
+} IconTextOverlay;
+
+#define UI_NO_ICON_OVERLAY_TEXT NULL
+
#define ICON_DEFAULT_HEIGHT 16
#define ICON_DEFAULT_WIDTH 16
@@ -105,7 +111,8 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- bool mono_border);
+ bool mono_border,
+ const struct IconTextOverlay *text_overlay);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
@@ -124,6 +131,9 @@ int UI_icon_from_library(const struct ID *id);
int UI_icon_from_object_mode(int mode);
int UI_icon_color_from_collection(const struct Collection *collection);
+void UI_icon_text_overlay_init_from_count(struct IconTextOverlay *text_overlay,
+ const int icon_indicator_number);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index c357b67722d..f0bf04ed408 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -103,7 +103,7 @@ enum eView2D_CommonViewTypes {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Foeard Declarations
+/** \name Forward Declarations
* \{ */
struct View2D;
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index 422fc34aa50..1f88d25af2b 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -6452,6 +6452,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string)
ui_but_add_shortcut(but, string, false);
}
+void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number)
+{
+ UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number);
+}
+
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
index e8f552e26a3..91b2f9613de 100644
--- a/source/blender/editors/interface/interface_context_path.cc
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -17,6 +17,8 @@
#include "UI_interface.hh"
#include "UI_resources.h"
+#include "RNA_prototypes.h"
+
#include "WM_api.h"
namespace blender::ui {
@@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path,
static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
icon_override;
- path.append({name, int(icon)});
+ if (&rna_type == &RNA_NodeTree) {
+ ID *id = (ID *)ptr;
+ path.append({name, int(icon), id->us});
+ }
+ else {
+ path.append({name, int(icon), 1});
+ }
}
/* -------------------------------------------------------------------- */
@@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
if (i > 0) {
uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
}
- uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ uiBut *but = uiItemL_ex(
+ sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false);
+ UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number);
}
}
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index ebfde05f516..60e1c0abfa1 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -89,7 +89,7 @@ static void ui_drop_material_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *dro
static char *ui_drop_material_tooltip(bContext *C,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
struct wmDropBox * /*drop*/)
{
PointerRNA rna_ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c080dce0f08..9a4f98ebcd6 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -415,8 +415,15 @@ static void vicon_collection_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_OUTLINER_COLLECTION,
+ aspect,
+ 1.0f,
+ 0.0f,
+ collection_color->color,
+ true,
+ UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \
@@ -444,7 +451,8 @@ static void vicon_strip_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true);
+ UI_icon_draw_ex(
+ x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_STRIP_COLOR_DRAW(index, color) \
@@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect(
{
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_LIBRARY_DATA_DIRECT,
+ aspect,
+ ICON_INDIRECT_DATA_ALPHA * alpha,
+ 0.0f,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
static void vicon_strip_color_draw_library_data_override_noneditable(
@@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable(
ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f,
0.0f,
NULL,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/* Dynamically render icon instead of rendering a plain color to a texture/buffer
@@ -923,7 +939,7 @@ static void init_internal_icons(void)
char iconfilestr[FILE_MAX];
if (icondir) {
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
/* if the image is missing bbuf will just be NULL */
bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL);
@@ -1047,7 +1063,7 @@ static void init_iconfile_list(struct ListBase *list)
/* check to see if the image is the right size, continue if not */
/* copying strings here should go ok, assuming that we never get back
* a complete path to file longer than 256 chars */
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, filename);
bbuf = IMB_loadiffname(iconfilestr, IB_rect);
if (bbuf) {
@@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x,
int ih,
float alpha,
const float rgb[3],
- bool with_border)
-{
- if (g_icon_draw_cache.enabled) {
+ bool with_border,
+ const IconTextOverlay *text_overlay)
+{
+ const float zoom_factor = w / UI_DPI_ICON_SIZE;
+ float text_width = 0.0f;
+
+ /* No need to show if too zoomed out, otherwise it just adds noise. */
+ const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') &&
+ (zoom_factor > 0.7f);
+
+ if (show_indicator) {
+ /* Handle the little numbers on top of the icon. */
+ uchar text_color[4];
+ UI_GetThemeColor3ubv(TH_TEXT, text_color);
+ text_color[3] = 255;
+
+ uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET;
+ fstyle_small.points *= zoom_factor;
+ fstyle_small.points *= 0.8f;
+
+ rcti text_rect = {
+ .xmax = x + UI_UNIT_X * zoom_factor,
+ .xmin = x,
+ .ymax = y,
+ .ymin = y,
+ };
+
+ UI_fontstyle_draw(&fstyle_small,
+ &text_rect,
+ text_overlay->text,
+ sizeof(text_overlay->text),
+ text_color,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_RIGHT,
+ });
+ text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X /
+ zoom_factor;
+ }
+
+ /* Draw the actual icon. */
+ if (!show_indicator && g_icon_draw_cache.enabled) {
icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border);
return;
}
@@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x,
GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0];
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON);
GPU_shader_bind(shader);
const int img_binding = GPU_shader_get_texture_binding(shader, "image");
@@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x,
GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2});
GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h});
+ GPU_shader_uniform_1f(shader, "text_width", text_width);
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
@@ -1786,7 +1841,8 @@ static void icon_draw_size(float x,
int draw_size,
const float desaturate,
const uchar mono_rgba[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
bTheme *btheme = UI_GetTheme();
const float fdraw_size = (float)draw_size;
@@ -1874,7 +1930,8 @@ static void icon_draw_size(float x,
di->data.texture.h,
alpha,
NULL,
- false);
+ false,
+ text_overlay);
}
else if (di->type == ICON_TYPE_MONO_TEXTURE) {
/* Monochrome icon that uses text or theme color. */
@@ -1908,7 +1965,8 @@ static void icon_draw_size(float x,
di->data.texture.h + 2 * border_texel,
color[3],
color,
- with_border);
+ with_border,
+ text_overlay);
}
else if (di->type == ICON_TYPE_BUFFER) {
@@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection)
void UI_icon_draw(float x, float y, int icon_id)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
+ icon_draw_size(x,
+ y,
+ icon_id,
+ aspect,
+ alpha,
+ ICON_SIZE_PREVIEW,
+ size,
+ false,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_ex(float x,
@@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
const int draw_size = get_draw_size(ICON_SIZE_ICON);
icon_draw_size(x,
@@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x,
draw_size,
desaturate,
mono_color,
- mono_border);
+ mono_border,
+ text_overlay);
+}
+
+void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay,
+ const int icon_indicator_number)
+{
+ /* The icon indicator is used as an aggregator, no need to show if it is 1. */
+ if (icon_indicator_number < 2) {
+ text_overlay->text[0] = '\0';
+ return;
+ }
+ BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number);
}
/* ********** Alert Icons ********** */
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 6ef7d346418..6ef81ad897e 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -23,6 +23,7 @@ struct ARegion;
struct AnimationEvalContext;
struct CurveMapping;
struct CurveProfile;
+struct IconTextOverlay;
struct ID;
struct ImBuf;
struct Main;
@@ -275,6 +276,9 @@ struct uiBut {
uiButPushedStateFunc pushed_state_func;
const void *pushed_state_arg;
+ /** Little indicator (e.g., counter) displayed on top of some icons. */
+ struct IconTextOverlay icon_overlay_text;
+
/* pointer back */
uiBlock *block;
};
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c906a5b36f1..496f72c089a 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
return but;
}
-void uiItemL_ex(
+uiBut *uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
{
uiBut *but = uiItemL_(layout, name, icon);
@@ -3248,6 +3248,8 @@ void uiItemL_ex(
if (redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
+
+ return but;
}
void uiItemL(uiLayout *layout, const char *name, int icon)
diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc
index 8b29f1075b8..e089642963d 100644
--- a/source/blender/editors/interface/interface_ops.cc
+++ b/source/blender/editors/interface/interface_ops.cc
@@ -1859,7 +1859,7 @@ static void edittranslation_find_po_file(const char *root,
/* First, full lang code. */
BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
- BLI_join_dirfile(path, maxlen, root, uilng);
+ BLI_path_join(path, maxlen, root, uilng);
BLI_path_append(path, maxlen, tstr);
if (BLI_is_file(path)) {
return;
@@ -1885,7 +1885,7 @@ static void edittranslation_find_po_file(const char *root,
BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
}
- BLI_join_dirfile(path, maxlen, root, tstr);
+ BLI_path_join(path, maxlen, root, tstr);
strcat(tstr, ".po");
BLI_path_append(path, maxlen, tstr);
if (BLI_is_file(path)) {
diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc
index 7a69e2f9b2f..24d8281aad8 100644
--- a/source/blender/editors/interface/interface_panel.cc
+++ b/source/blender/editors/interface/interface_panel.cc
@@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
0.7f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
@@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
1.0f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc
index 9dd6f95e190..f443dd43a3a 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.cc
+++ b/source/blender/editors/interface/interface_region_menu_pie.cc
@@ -222,7 +222,7 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
- pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
+ pie = UI_pie_menu_begin(C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE, event);
layout = UI_pie_menu_layout(pie);
UI_menutype_draw(C, mt, layout);
diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc
index f88cabb2b70..569f657a544 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.cc
+++ b/source/blender/editors/interface/interface_region_menu_popup.cc
@@ -175,11 +175,7 @@ struct uiPopupMenu {
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
- uiBlock *block;
uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup);
- int minwidth, width, height;
- char direction;
- bool flip;
if (pup->menu_func) {
pup->block->handle = handle;
@@ -188,6 +184,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
}
/* Find block minimum width. */
+ int minwidth;
if (uiLayoutGetUnitsX(pup->layout) != 0.0f) {
/* Use the minimum width from the layout if it's set. */
minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X;
@@ -207,6 +204,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
}
/* Find block direction. */
+ char direction;
if (pup->but) {
if (pup->block->direction != 0) {
/* allow overriding the direction from menu_func */
@@ -220,9 +218,9 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
direction = UI_DIR_DOWN;
}
- flip = (direction == UI_DIR_DOWN);
+ bool flip = (direction == UI_DIR_DOWN);
- block = pup->block;
+ uiBlock *block = pup->block;
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
@@ -232,6 +230,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
block->direction = direction;
+ int width, height;
UI_block_layout_resolve(block, &width, &height);
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
@@ -318,7 +317,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
{
wmWindow *window = CTX_wm_window(C);
const uiStyle *style = UI_style_get_dpi();
- uiPopupBlockHandle *handle;
uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN);
@@ -357,7 +355,8 @@ uiPopupBlockHandle *ui_popup_menu_create(
pup->menu_func = menu_func;
pup->menu_arg = arg;
- handle = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
if (!but) {
handle->popup = true;
@@ -384,7 +383,6 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
{
const uiStyle *style = UI_style_get_dpi();
uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
- uiBut *but;
pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN);
pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
@@ -423,7 +421,7 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
"");
}
else {
- but = uiDefBut(
+ uiBut *but = uiDefBut(
pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, "");
but->drawflag = UI_BUT_TEXT_LEFT;
}
@@ -448,20 +446,20 @@ void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *b
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *menu;
- uiBut *but = nullptr;
- ARegion *butregion = nullptr;
pup->popup = true;
pup->mx = window->eventstate->xy[0];
pup->my = window->eventstate->xy[1];
+ uiBut *but = nullptr;
+ ARegion *butregion = nullptr;
if (pup->but) {
but = pup->but;
butregion = pup->butregion;
}
- menu = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
+ uiPopupBlockHandle *menu = ui_popup_block_create(
+ C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
menu->popup = true;
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
@@ -545,8 +543,6 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports)
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
{
- uiPopupMenu *pup;
- uiLayout *layout;
MenuType *mt = WM_menutype_find(idname, true);
if (mt == nullptr) {
@@ -559,8 +555,9 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
- pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(
+ C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
UI_menutype_draw(C, mt, layout);
@@ -579,9 +576,9 @@ void UI_popup_block_invoke_ex(
bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free, bool can_refresh)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *handle;
- handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, arg_free);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, nullptr, nullptr, func, nullptr, arg, arg_free);
handle->popup = true;
/* It can be useful to disable refresh (even though it will work)
@@ -607,9 +604,9 @@ void UI_popup_block_ex(bContext *C,
wmOperator *op)
{
wmWindow *window = CTX_wm_window(C);
- uiPopupBlockHandle *handle;
- handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, nullptr);
+ uiPopupBlockHandle *handle = ui_popup_block_create(
+ C, nullptr, nullptr, func, nullptr, arg, nullptr);
handle->popup = true;
handle->retvalue = 1;
handle->can_refresh = true;
diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc
index e93bc4c4bfe..e574cb30b23 100644
--- a/source/blender/editors/interface/interface_region_popup.cc
+++ b/source/blender/editors/interface/interface_region_popup.cc
@@ -69,7 +69,6 @@ static void ui_popup_block_position(wmWindow *window,
/* Compute button position in window coordinates using the source
* button region/block, to position the popup attached to it. */
rctf butrct;
-
if (!handle->refresh) {
ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
@@ -417,14 +416,13 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
{
const float xmin_orig = block->rect.xmin;
const int margin = UI_SCREEN_MARGIN;
- int winx, winy;
if (block->flag & UI_BLOCK_NO_WIN_CLIP) {
return;
}
- winx = WM_window_pixels_x(window);
- winy = WM_window_pixels_y(window);
+ const int winx = WM_window_pixels_x(window);
+ const int winy = WM_window_pixels_y(window);
/* shift to left if outside of view */
if (block->rect.xmax > winx - margin) {
@@ -549,7 +547,6 @@ uiBlock *ui_popup_block_refresh(bContext *C,
void *arg = handle->popup_create_vars.arg;
uiBlock *block_old = static_cast<uiBlock *>(region->uiblocks.first);
- uiBlock *block;
handle->refresh = (block_old != nullptr);
@@ -561,6 +558,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
#endif
/* create ui block */
+ uiBlock *block;
if (create_func) {
block = create_func(C, region, arg);
}
@@ -618,16 +616,14 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block->flag & UI_BLOCK_RADIAL) {
const int win_width = UI_SCREEN_MARGIN;
- int winx, winy;
-
- int x_offset = 0, y_offset = 0;
- winx = WM_window_pixels_x(window);
- winy = WM_window_pixels_y(window);
+ const int winx = WM_window_pixels_x(window);
+ const int winy = WM_window_pixels_y(window);
copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned);
/* only try translation if area is large enough */
+ int x_offset = 0;
if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) {
if (block->rect.xmin < win_width) {
x_offset += win_width - block->rect.xmin;
@@ -637,6 +633,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
}
}
+ int y_offset = 0;
if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) {
if (block->rect.ymin < win_width) {
y_offset += win_width - block->rect.ymin;
@@ -756,9 +753,6 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
{
wmWindow *window = CTX_wm_window(C);
uiBut *activebut = UI_context_active_but_get(C);
- static ARegionType type;
- ARegion *region;
- uiBlock *block;
/* disable tooltips from buttons below */
if (activebut) {
@@ -787,9 +781,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
handle->can_refresh = false;
/* create area region */
- region = ui_region_temp_add(CTX_wm_screen(C));
+ ARegion *region = ui_region_temp_add(CTX_wm_screen(C));
handle->region = region;
+ static ARegionType type;
memset(&type, 0, sizeof(ARegionType));
type.draw = ui_block_region_draw;
type.layout = ui_block_region_refresh;
@@ -798,7 +793,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_region_handlers_add(&region->handlers);
- block = ui_popup_block_refresh(C, handle, butregion, but);
+ uiBlock *block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
/* keep centered on window resizing */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d21f969e431..a3259831c9f 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3269,7 +3269,7 @@ void uiTemplatePreview(uiLayout *layout,
uiDefButS(block,
UI_BTYPE_ROW,
B_MATPRV,
- IFACE_("World"),
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WORLD, "World"),
0,
0,
UI_UNIT_X * 10,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 6ba80e2e0d9..1bad9b34a72 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1420,21 +1420,25 @@ static void widget_draw_icon(
/* to indicate draggable */
if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
if (has_theme) {
alpha *= 0.8f;
}
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else {
const bTheme *btheme = UI_GetTheme();
const float desaturate = 1.0 - btheme->tui.icon_saturation;
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text);
}
}
@@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
GPU_blend(GPU_BLEND_ALPHA);
/* XXX scale weak get from fstyle? */
- UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
+ UI_icon_draw_ex(
+ xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index d4855f470ff..100d56a6b0d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -658,7 +658,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
ot->name = "Import Alembic";
ot->description = "Load an Alembic archive";
ot->idname = "WM_OT_alembic_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_alembic_import_invoke;
ot->exec = wm_alembic_import_exec;
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 1048d0eca32..a630f150e0e 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -770,14 +770,12 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->name = "Import COLLADA";
ot->description = "Load a Collada file";
ot->idname = "WM_OT_collada_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = WM_operator_filesel;
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
- // ot->flag = OPTYPE_PRESET;
-
ot->ui = wm_collada_import_draw;
WM_operator_properties_filesel(ot,
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index c7a6b20af7b..5325965e9a5 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -111,7 +111,7 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
char file_path[FILE_MAX];
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
- BLI_join_dirfile(file_path, sizeof(file_path), directory, filename);
+ BLI_path_join(file_path, sizeof(file_path), directory, filename);
MEM_freeN(filename);
/* Do Import. */
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index cb8eafeb52d..27994af8fe7 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -81,7 +81,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
- export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.global_scale = RNA_float_get(op->ptr, "global_scale");
export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers");
export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
@@ -122,7 +122,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
col = uiLayoutColumn(box, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
- uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "forward_axis", UI_ITEM_R_EXPAND, IFACE_("Forward Axis"), ICON_NONE);
@@ -301,15 +301,16 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
RNA_def_property_update_runtime(prop, (void *)forward_axis_update);
prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_property_update_runtime(prop, (void *)up_axis_update);
- RNA_def_float(ot->srna,
- "scaling_factor",
- 1.0f,
- 0.001f,
- 10000.0f,
- "Scale",
- "Upscale the object by this factor",
- 0.01,
- 1000.0f);
+ RNA_def_float(
+ ot->srna,
+ "global_scale",
+ 1.0f,
+ 0.0001f,
+ 10000.0f,
+ "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f,
+ 10000.0f);
/* File Writer options. */
RNA_def_boolean(
ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
@@ -405,6 +406,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
{
struct OBJImportParams import_params;
RNA_string_get(op->ptr, "filepath", import_params.filepath);
+ import_params.global_scale = RNA_float_get(op->ptr, "global_scale");
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
import_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
@@ -425,8 +427,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
for (int i = 0; i < files_len; i++) {
RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(
- import_params.filepath, sizeof(import_params.filepath), dir_only, file_only);
+ BLI_path_join(import_params.filepath, sizeof(import_params.filepath), dir_only, file_only);
import_params.clear_selection = (i == 0);
OBJ_import(C, &import_params);
}
@@ -459,6 +460,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(box, IFACE_("Transform"), ICON_OBJECT_DATA);
uiLayout *col = uiLayoutColumn(box, false);
uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE);
uiItemR(sub, imfptr, "clamp_size", 0, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
@@ -489,7 +491,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_obj_import_invoke;
ot->exec = wm_obj_import_exec;
@@ -506,6 +508,16 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
FILE_SORT_DEFAULT);
RNA_def_float(
ot->srna,
+ "global_scale",
+ 1.0f,
+ 0.0001f,
+ 10000.0f,
+ "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f,
+ 10000.0f);
+ RNA_def_float(
+ ot->srna,
"clamp_size",
0.0f,
0.0f,
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
index c98e5beaf3b..bbdb494e48a 100644
--- a/source/blender/editors/io/io_stl_ops.c
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -49,7 +49,7 @@ static int wm_stl_import_execute(bContext *C, wmOperator *op)
for (int i = 0; i < files_len; i++) {
RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only);
+ BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only);
STL_import(C, &params);
}
}
@@ -95,7 +95,7 @@ void WM_OT_stl_import(struct wmOperatorType *ot)
ot->exec = wm_stl_import_execute;
ot->poll = WM_operator_winactive;
ot->check = wm_stl_import_check;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index eb80cabcd7f..c776fbf0dd7 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -500,7 +500,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_import_draw;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index e9897021b4a..a147594b25b 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -100,7 +100,7 @@ typedef struct KnifeColors {
/* Knife-tool Operator. */
typedef struct KnifeVert {
Object *ob;
- uint base_index;
+ uint ob_index;
BMVert *v; /* Non-NULL if this is an original vert. */
ListBase edges;
ListBase faces;
@@ -142,7 +142,7 @@ typedef struct KnifeLineHit {
KnifeVert *v;
BMFace *f;
Object *ob;
- uint base_index;
+ uint ob_index;
} KnifeLineHit;
typedef struct KnifePosData {
@@ -156,7 +156,7 @@ typedef struct KnifePosData {
KnifeEdge *edge;
BMFace *bmface;
Object *ob; /* Object of the vert, edge or bmface. */
- uint base_index;
+ uint ob_index;
/* When true, the cursor isn't over a face. */
bool is_space;
@@ -182,7 +182,7 @@ typedef struct KnifeBVH {
BVHTree *tree; /* Knife Custom BVH Tree. */
BMLoop *(*looptris)[3]; /* Used by #knife_bvh_raycast_cb to store the intersecting looptri. */
float uv[2]; /* Used by #knife_bvh_raycast_cb to store the intersecting uv. */
- uint base_index;
+ uint ob_index;
/* Use #bm_ray_cast_cb_elem_not_in_face_check. */
bool (*filter_cb)(BMFace *f, void *userdata);
@@ -218,6 +218,7 @@ typedef struct KnifeTool_OpData {
/* Used for swapping current object when in multi-object edit mode. */
Object **objects;
uint objects_len;
+ bool objects_free;
/** Array `objects_len` length of additional per-object data. */
KnifeObjectInfo *objects_info;
@@ -1158,11 +1159,11 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
* \{ */
static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
- int base_index,
+ int ob_index,
int tri_index,
int tri_index_buf[3])
{
- const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index];
if (obinfo->tri_indices) {
return obinfo->tri_indices[tri_index];
}
@@ -1173,25 +1174,25 @@ static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd,
}
static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd,
- int base_index,
+ int ob_index,
int tri_index,
float cos[3][3])
{
- const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index];
int tri_ind_buf[3];
- const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf);
+ const int *tri_ind = knife_bm_tri_index_get(kcd, ob_index, tri_index, tri_ind_buf);
for (int i = 0; i < 3; i++) {
copy_v3_v3(cos[i], obinfo->cagecos[tri_ind[i]]);
}
}
static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd,
- int base_index,
+ int ob_index,
int tri_index,
float cos[3][3])
{
- knife_bm_tri_cagecos_get(kcd, base_index, tri_index, cos);
- const Object *ob = kcd->objects[base_index];
+ knife_bm_tri_cagecos_get(kcd, ob_index, tri_index, cos);
+ const Object *ob = kcd->objects[ob_index];
for (int i = 0; i < 3; i++) {
mul_m4_v3(ob->obmat, cos[i]);
}
@@ -1236,9 +1237,9 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
bool test_fn_ret = false;
/* Calculate tottri. */
- for (uint b = 0; b < kcd->objects_len; b++) {
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
ob_tottri = 0;
- ob = kcd->objects[b];
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
for (int i = 0; i < em->tottri; i++) {
@@ -1268,8 +1269,8 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
* Don't forget to update #knife_bvh_intersect_plane!
*/
tottri = 0;
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
looptris = em->looptris;
@@ -1286,7 +1287,7 @@ static void knife_bvh_init(KnifeTool_OpData *kcd)
}
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, i, tri_cos);
BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3);
}
@@ -1324,10 +1325,10 @@ static void knife_bvh_raycast_cb(void *userdata,
int tottri;
tottri = 0;
- uint b = 0;
- for (; b < kcd->objects_len; b++) {
+ uint ob_index = 0;
+ for (; ob_index < kcd->objects_len; ob_index++) {
index -= tottri;
- ob = kcd->objects[b];
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
tottri = em->tottri;
if (index < tottri) {
@@ -1343,7 +1344,7 @@ static void knife_bvh_raycast_cb(void *userdata,
}
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, index, tri_cos);
isect = (ray->radius > 0.0f ?
isect_ray_tri_epsilon_v3(
ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) :
@@ -1370,7 +1371,7 @@ static void knife_bvh_raycast_cb(void *userdata,
kcd->bvh.looptris = em->looptris;
copy_v2_v2(kcd->bvh.uv, uv);
- kcd->bvh.base_index = b;
+ kcd->bvh.ob_index = ob_index;
}
}
@@ -1382,7 +1383,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
- uint *r_base_index)
+ uint *r_ob_index)
{
BMFace *face;
BVHTreeRayHit hit;
@@ -1399,7 +1400,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos);
interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
@@ -1411,8 +1412,8 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd,
*r_dist = hit.dist;
}
- if (r_base_index) {
- *r_base_index = kcd->bvh.base_index;
+ if (r_ob_index) {
+ *r_ob_index = kcd->bvh.ob_index;
}
return face;
@@ -1428,7 +1429,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
- uint *r_base_index,
+ uint *r_ob_index,
bool (*filter_cb)(BMFace *f, void *userdata),
void *filter_userdata)
{
@@ -1453,7 +1454,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
/* Hits returned in world space. */
if (r_hitout) {
float tri_cos[3][3];
- knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos);
interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv);
if (r_cagehit) {
@@ -1465,8 +1466,8 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd,
*r_dist = hit.dist;
}
- if (r_base_index) {
- *r_base_index = kcd->bvh.base_index;
+ if (r_ob_index) {
+ *r_ob_index = kcd->bvh.ob_index;
}
return face;
@@ -1726,7 +1727,7 @@ static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd)
}
/* Get a KnifeVert wrapper for an existing BMVert. */
-static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint base_index)
+static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint ob_index)
{
KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
const float *cageco;
@@ -1736,7 +1737,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
BMFace *f;
if (BM_elem_index_get(v) >= 0) {
- cageco = kcd->objects_info[base_index].cagecos[BM_elem_index_get(v)];
+ cageco = kcd->objects_info[ob_index].cagecos[BM_elem_index_get(v)];
}
else {
cageco = v->co;
@@ -1748,7 +1749,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
kfv = new_knife_vert(kcd, v->co, cageco_ws);
kfv->v = v;
kfv->ob = ob;
- kfv->base_index = base_index;
+ kfv->ob_index = ob_index;
BLI_ghash_insert(kcd->origvertmap, v, kfv);
BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) {
@@ -1760,7 +1761,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob
}
/* Get a KnifeEdge wrapper for an existing BMEdge. */
-static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint base_index)
+static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint ob_index)
{
KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
if (!kfe) {
@@ -1769,8 +1770,8 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob
kfe = new_knife_edge(kcd);
kfe->e = e;
- kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, base_index);
- kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, base_index);
+ kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, ob_index);
+ kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, ob_index);
knife_add_to_vert_edges(kcd, kfe);
@@ -1784,10 +1785,7 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob
return kfe;
}
-static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
- Object *ob,
- uint base_index,
- BMFace *f)
+static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f)
{
ListBase *list = BLI_ghash_lookup(kcd->kedgefacemap, f);
@@ -1798,7 +1796,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
list = knife_empty_list(kcd);
BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) {
- knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, base_index));
+ knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, ob_index));
}
BLI_ghash_insert(kcd->kedgefacemap, f, list);
@@ -1809,7 +1807,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd,
static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f)
{
- knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->base_index, f), kfe);
+ knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->ob_index, f), kfe);
knife_append_list(kcd, &kfe->faces, f);
}
@@ -1826,7 +1824,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd,
newkfe->v1 = kfe->v1;
newkfe->v2 = new_knife_vert(kcd, co, cageco);
newkfe->v2->ob = kfe->v1->ob;
- newkfe->v2->base_index = kfe->v1->base_index;
+ newkfe->v2->ob_index = kfe->v1->ob_index;
newkfe->v2->is_cut = true;
if (kfe->e) {
knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e);
@@ -2123,7 +2121,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd,
BLI_assert(lh1->f);
kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit);
kfe->v1->ob = lh1->ob;
- kfe->v1->base_index = lh1->base_index;
+ kfe->v1->ob_index = lh1->ob_index;
kfe->v1->is_cut = true;
kfe->v1->is_face = true;
knife_append_list(kcd, &kfe->v1->faces, lh1->f);
@@ -2141,7 +2139,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd,
BLI_assert(lh2->f);
kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit);
kfe->v2->ob = lh2->ob;
- kfe->v2->base_index = lh2->base_index;
+ kfe->v2->ob_index = lh2->ob_index;
kfe->v2->is_cut = true;
kfe->v2->is_face = true;
knife_append_list(kcd, &kfe->v2->faces, lh2->f);
@@ -2567,7 +2565,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
const float v1[3],
const float v2[3],
Object *ob,
- uint base_index,
+ uint ob_index,
BMFace *f,
const float face_tol_sq,
float hit_co[3],
@@ -2600,7 +2598,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
break;
}
- knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos);
+ knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, tri_i, tri_cos);
/* Using epsilon test in case ray is directly through an internal
* tessellation edge and might not hit either tessellation tri with
@@ -2617,7 +2615,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
}
interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv);
/* Now check that far enough away from verts and edges. */
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
kfe = ref->ref;
if (kfe->is_invalid) {
@@ -2651,11 +2649,11 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
float ws[3];
INIT_MINMAX(min, max);
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
- const float(*cagecos)[3] = kcd->objects_info[b].cagecos;
+ const float(*cagecos)[3] = kcd->objects_info[ob_index].cagecos;
if (cagecos) {
for (int i = 0; i < em->bm->totvert; i++) {
copy_v3_v3(ws, cagecos[i]);
@@ -2930,11 +2928,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
Object *ob;
BMEditMesh *em;
- uint b = 0;
for (i = 0, result = results; i < tot; i++, result++) {
- for (b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ uint ob_index = 0;
+ for (ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
if (*result >= 0 && *result < em->tottri) {
ls = (BMLoop **)em->looptris[*result];
@@ -2956,9 +2954,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
/* Don't care what the value is except that it is non-NULL, for iterator. */
BLI_smallhash_insert(&faces, (uintptr_t)f, f);
- BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)b);
+ BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)ob_index);
- list = knife_get_face_kedges(kcd, ob, b, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
kfe = ref->ref;
if (kfe->is_invalid) {
@@ -3033,7 +3031,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
hit.ob = v->ob;
- hit.base_index = v->base_index;
+ hit.ob_index = v->ob_index;
copy_v3_v3(hit.hit, v->co);
copy_v3_v3(hit.cagehit, v->cageco);
copy_v2_v2(hit.schit, s);
@@ -3109,7 +3107,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
transform_point_by_seg_v3(
hit.hit, p_cage, kfe->v1->co, kfe->v2->co, kfe->v1->cageco, kfe->v2->cageco);
hit.ob = kfe->v1->ob;
- hit.base_index = kfe->v1->base_index;
+ hit.ob_index = kfe->v1->ob_index;
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, sint);
hit.perc = lambda;
@@ -3129,16 +3127,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
float p[3], p_cage[3];
- uint base_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f);
- ob = kcd->objects[base_index];
+ uint ob_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f);
+ ob = kcd->objects[ob_index];
if (use_hit_prev &&
- knife_ray_intersect_face(kcd, s1, v1, v3, ob, base_index, f, face_tol_sq, p, p_cage)) {
+ knife_ray_intersect_face(kcd, s1, v1, v3, ob, ob_index, f, face_tol_sq, p, p_cage)) {
if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
hit.ob = ob;
- hit.base_index = base_index;
+ hit.ob_index = ob_index;
copy_v3_v3(hit.hit, p);
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s1);
@@ -3148,12 +3146,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
if (use_hit_curr &&
- knife_ray_intersect_face(kcd, s2, v2, v4, ob, base_index, f, face_tol_sq, p, p_cage)) {
+ knife_ray_intersect_face(kcd, s2, v2, v4, ob, ob_index, f, face_tol_sq, p, p_cage)) {
if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
hit.ob = ob;
- hit.base_index = base_index;
+ hit.ob_index = ob_index;
copy_v3_v3(hit.hit, p);
copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s2);
@@ -3205,7 +3203,7 @@ static void knife_pos_data_clear(KnifePosData *kpd)
static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
Object **r_ob,
- uint *r_base_index,
+ uint *r_ob_index,
bool *is_space,
float r_co[3],
float r_cageco[3])
@@ -3221,7 +3219,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
sub_v3_v3v3(ray, origin_ofs, origin);
normalize_v3_v3(ray_normal, ray);
- f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_base_index);
+ f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_ob_index);
if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) {
f = NULL;
@@ -3232,7 +3230,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
}
if (f) {
- *r_ob = kcd->objects[*r_base_index];
+ *r_ob = kcd->objects[*r_ob_index];
}
else {
if (kcd->is_interactive) {
@@ -3267,7 +3265,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd,
static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd,
const float radius,
Object *ob,
- uint base_index,
+ uint ob_index,
BMFace *f,
const float cageco[3])
{
@@ -3280,7 +3278,7 @@ static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd,
knife_project_v2(kcd, cageco, sco);
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
int i;
@@ -3329,7 +3327,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
if (!kcd->curr.is_space) {
density = (float)knife_sample_screen_density_from_closest_face(
- kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.cage);
+ kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.cage);
}
return density ? min_ff(maxsize / ((float)density * 0.5f), maxsize) : maxsize;
@@ -3388,7 +3386,7 @@ static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd,
/* p is closest point on edge to the mouse cursor. */
static KnifeEdge *knife_find_closest_edge_of_face(
- KnifeTool_OpData *kcd, Object *ob, uint base_index, BMFace *f, float p[3], float cagep[3])
+ KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f, float p[3], float cagep[3])
{
float sco[2];
float maxdist;
@@ -3414,7 +3412,7 @@ static KnifeEdge *knife_find_closest_edge_of_face(
knife_project_v2(kcd, cagep, sco);
/* Look through all edges associated with this face. */
- list = knife_get_face_kedges(kcd, ob, base_index, f);
+ list = knife_get_face_kedges(kcd, ob, ob_index, f);
for (ref = list->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
float kfv1_sco[2], kfv2_sco[2], test_cagep[3];
@@ -3479,7 +3477,7 @@ static KnifeEdge *knife_find_closest_edge_of_face(
* this is important for angle snap, which uses the previous mouse position. */
edgesnap = new_knife_vert(kcd, p, cagep);
edgesnap->ob = ob;
- edgesnap->base_index = base_index;
+ edgesnap->ob_index = ob_index;
knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval);
}
@@ -3906,14 +3904,14 @@ static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[
kcd->curr.ob = kcd->vc.obedit;
kcd->curr.bmface = knife_find_closest_face(kcd,
&kcd->curr.ob,
- &kcd->curr.base_index,
+ &kcd->curr.ob_index,
&kcd->curr.is_space,
kcd->curr.co,
kcd->curr.cage);
if (kcd->curr.bmface) {
kcd->curr.edge = knife_find_closest_edge_of_face(
- kcd, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
+ kcd, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
}
if (kcd->curr.edge) {
@@ -4017,7 +4015,7 @@ static void knifetool_undo(KnifeTool_OpData *kcd)
static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
Object *ob,
- uint base_index,
+ uint ob_index,
bool use_tri_indices)
{
@@ -4027,7 +4025,7 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT);
- KnifeObjectInfo *obinfo = &kcd->objects_info[base_index];
+ KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index];
obinfo->em = em_eval;
obinfo->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
@@ -4045,10 +4043,10 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd,
}
}
-static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index)
+static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint ob_index)
{
- MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos);
- MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices);
+ MEM_SAFE_FREE(kcd->objects_info[ob_index].cagecos);
+ MEM_SAFE_FREE(kcd->objects_info[ob_index].tri_indices);
}
/** \} */
@@ -4081,6 +4079,8 @@ static void knife_init_colors(KnifeColors *colors)
/* called when modal loop selection gets set up... */
static void knifetool_init(ViewContext *vc,
KnifeTool_OpData *kcd,
+ Object **objects,
+ const int objects_len,
const bool only_select,
const bool cut_through,
const bool xray,
@@ -4101,16 +4101,24 @@ static void knifetool_init(ViewContext *vc,
kcd->scene = scene;
kcd->region = vc->region;
- kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len);
+ if (objects) {
+ kcd->objects = objects;
+ kcd->objects_len = objects_len;
+ kcd->objects_free = false;
+ }
+ else {
+ kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len);
+ kcd->objects_free = true;
+ }
Object *ob;
BMEditMesh *em;
kcd->objects_info = MEM_callocN(sizeof(*kcd->objects_info) * kcd->objects_len, "knife cagecos");
- for (uint b = 0; b < kcd->objects_len; b++) {
- ob = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ ob = kcd->objects[ob_index];
em = BKE_editmesh_from_object(ob);
- knifetool_init_obinfo(kcd, ob, b, use_tri_indices);
+ knifetool_init_obinfo(kcd, ob, ob_index, use_tri_indices);
/* Can't usefully select resulting edges in face mode. */
kcd->select_result = (em->selectmode != SCE_SELECT_FACE);
@@ -4225,7 +4233,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
}
/* Free object bases. */
- MEM_freeN(kcd->objects);
+ if (kcd->objects_free) {
+ MEM_freeN(kcd->objects);
+ }
/* Destroy kcd itself. */
MEM_freeN(kcd);
@@ -4318,9 +4328,15 @@ static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *
/* Called on tool confirmation. */
static void knifetool_finish_ex(KnifeTool_OpData *kcd)
{
- for (uint b = 0; b < kcd->objects_len; b++) {
- Object *ob = kcd->objects[b];
+ /* Separate pre/post passes are needed because `em->looptris` recalculation from the 'post' pass
+ * causes causes triangle indices in #KnifeTool_OpData.bvh to get out of sync.
+ * So perform all the cuts before doing any mesh recalculation, see: T101721. */
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_pre(kcd, ob);
+ }
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_post(kcd, ob);
}
}
@@ -4789,6 +4805,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_init(&vc,
kcd,
+ NULL,
+ 0,
only_select,
cut_through,
xray,
@@ -4802,8 +4820,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
BMEditMesh *em;
bool faces_selected = false;
- for (uint b = 0; b < kcd->objects_len; b++) {
- obedit = kcd->objects[b];
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ obedit = kcd->objects[ob_index];
em = BKE_editmesh_from_object(obedit);
if (em->bm->totfacesel != 0) {
faces_selected = true;
@@ -4942,7 +4960,12 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
+void EDBM_mesh_knife(ViewContext *vc,
+ Object **objects,
+ const int objects_len,
+ LinkNode *polys,
+ bool use_tag,
+ bool cut_through)
{
KnifeTool_OpData *kcd;
@@ -4959,6 +4982,8 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
knifetool_init(vc,
kcd,
+ objects,
+ objects_len,
only_select,
cut_through,
xray,
@@ -5000,18 +5025,21 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
/* Finish. */
{
- Object *ob;
- BMEditMesh *em;
- for (uint b = 0; b < kcd->objects_len; b++) {
-
- ob = kcd->objects[b];
- em = BKE_editmesh_from_object(ob);
+ /* See #knifetool_finish_ex for why multiple passes are needed. */
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_tag) {
BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
knifetool_finish_single_pre(kcd, ob);
+ }
+
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
+ Object *ob = kcd->objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
/* Tag faces inside! */
if (use_tag) {
@@ -5104,9 +5132,12 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
#undef F_ISECT_SET_UNKNOWN
#undef F_ISECT_SET_OUTSIDE
}
+ }
+ for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) {
/* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and
* the doc-string for #knifetool_finish_single_post. */
+ Object *ob = kcd->objects[ob_index];
knifetool_finish_single_post(kcd, ob);
}
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index e27d19ab000..6004a2943a2 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -132,22 +132,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
ViewContext vc;
em_setup_viewcontext(C, &vc);
- /* TODO: Ideally meshes would occlude each other, currently they don't
- * since each knife-project runs as a separate operation. */
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
vc.scene, vc.view_layer, vc.v3d, &objects_len);
+
+ EDBM_mesh_knife(&vc, objects, objects_len, polys, true, cut_through);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
ED_view3d_viewcontext_init_object(&vc, obedit);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_mesh_knife(&vc, polys, true, cut_through);
-
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- EDBM_selectmode_disable_multi(C, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index fdf4746ab09..070f748c78e 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -88,7 +88,7 @@ static int geometry_extract_apply(bContext *C,
ED_object_sculptmode_exit(C, depsgraph);
- BKE_sculpt_mask_layers_ensure(ob, NULL);
+ BKE_sculpt_mask_layers_ensure(depsgraph, bmain, ob, NULL);
/* Ensures that deformation from sculpt mode is taken into account before duplicating the mesh to
* extract the geometry. */
@@ -481,7 +481,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
View3D *v3d = CTX_wm_view3d(C);
- BKE_sculpt_mask_layers_ensure(ob, NULL);
+ BKE_sculpt_mask_layers_ensure(NULL, NULL, ob, NULL);
Mesh *mesh = ob->data;
Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id);
diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc
index 0d1e3c08d84..76d0bab8a52 100644
--- a/source/blender/editors/mesh/editmesh_select.cc
+++ b/source/blender/editors/mesh/editmesh_select.cc
@@ -22,7 +22,9 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "BKE_report.h"
#include "WM_api.h"
@@ -1065,8 +1067,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
{
Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph,
static_cast<ID *>(obedit->data));
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
+ if (me_eval->runtime->edit_data) {
+ coords = me_eval->runtime->edit_data->vertexCos;
}
}
diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc
index f5056021f7d..5c837e61a79 100644
--- a/source/blender/editors/mesh/editmesh_undo.cc
+++ b/source/blender/editors/mesh/editmesh_undo.cc
@@ -101,7 +101,7 @@ struct UndoMesh {
int shapenr;
#ifdef USE_ARRAY_STORE
- /* N`ull arrays are considered empty */
+ /* Null arrays are considered empty. */
struct { /* most data is stored as 'custom' data */
BArrayCustomData *vdata, *edata, *ldata, *pdata;
BArrayState **keyblocks;
@@ -231,7 +231,7 @@ static void um_arraystore_cd_compact(CustomData *cdata,
}
bcd->states[i] = BLI_array_store_state_add(
- bs, layer->data, (size_t)data_len * stride, state_reference);
+ bs, layer->data, size_t(data_len) * stride, state_reference);
}
else {
bcd->states[i] = nullptr;
@@ -334,7 +334,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool
um_ref->store.keyblocks[i] :
nullptr;
um->store.keyblocks[i] = BLI_array_store_state_add(
- bs, keyblock->data, (size_t)keyblock->totelem * stride, state_reference);
+ bs, keyblock->data, size_t(keyblock->totelem) * stride, state_reference);
}
if (keyblock->data) {
@@ -352,7 +352,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool
BArrayStore *bs = BLI_array_store_at_size_ensure(
&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE);
um->store.mselect = BLI_array_store_state_add(
- bs, me->mselect, (size_t)me->totselect * stride, state_reference);
+ bs, me->mselect, size_t(me->totselect) * stride, state_reference);
}
/* keep me->totselect for validation */
@@ -597,6 +597,11 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo
* on it. Necessary to use the attribute API. */
strcpy(um->me.id.name, "MEundomesh_from_editmesh");
+ /* Runtime data is necessary for some asserts in other code, and the overhead of creating it for
+ * undo meshes should be low. */
+ BLI_assert(um->me.runtime == nullptr);
+ um->me.runtime = new blender::bke::MeshRuntime();
+
CustomData_MeshMasks cd_mask_extra{};
cd_mask_extra.vmask = CD_MASK_SHAPE_KEYINDEX;
BMeshToMeshParams params{};
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index e6505715324..0e20bb18595 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -18,6 +18,7 @@ struct BMElem;
struct BMOperator;
struct EnumPropertyItem;
struct LinkNode;
+struct Object;
struct bContext;
struct wmKeyConfig;
struct wmKeyMap;
@@ -177,6 +178,8 @@ void MESH_OT_knife_project(struct wmOperatorType *ot);
* \param use_tag: When set, tag all faces inside the polylines.
*/
void EDBM_mesh_knife(struct ViewContext *vc,
+ struct Object **objects,
+ int objects_len,
struct LinkNode *polys,
bool use_tag,
bool cut_through);
diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc
index 2210cc67bff..4d75ab7f041 100644
--- a/source/blender/editors/mesh/meshtools.cc
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -1335,7 +1335,7 @@ struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
VertPickData *data = static_cast<VertPickData *>(userData);
if (data->hide_vert && data->hide_vert[index]) {
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 3ce39b695e0..f6eee7c0c9e 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -3556,11 +3556,62 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/** \name Duplicate Object Operator
* \{ */
+static void object_add_sync_base_collection(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new)
+{
+ if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
+ BKE_collection_object_add_from(bmain, scene, base_src->object, object_new);
+ }
+ else {
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, object_new);
+ }
+}
+
+static void object_add_sync_local_view(Base *base_src, Base *base_new)
+{
+ base_new->local_view_bits = base_src->local_view_bits;
+}
+
+static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new)
+{
+ /* 1) duplis should end up in same collection as the original
+ * 2) Rigid Body sim participants MUST always be part of a collection...
+ */
+ /* XXX: is 2) really a good measure here? */
+ if (object_src->rigidbody_object || object_src->rigidbody_constraint) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if (BKE_collection_has_object(collection, object_src)) {
+ BKE_collection_object_add(bmain, collection, object_new);
+ }
+ }
+ }
+}
+
/**
* - Assumes `id.new` is correct.
* - Leaves selection of base/object unaltered.
* - Sets #ID.newid pointers.
*/
+static void object_add_duplicate_internal(Main *bmain,
+ Object *ob,
+ const eDupli_ID_Flags dupflag,
+ const eLibIDDuplicateFlags duplicate_options,
+ Object **r_ob_new)
+{
+ if (ob->mode & OB_MODE_POSE) {
+ return;
+ }
+
+ Object *obn = static_cast<Object *>(
+ ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
+ if (r_ob_new) {
+ *r_ob_new = obn;
+ }
+ DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ return;
+}
+
static Base *object_add_duplicate_internal(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -3569,49 +3620,25 @@ static Base *object_add_duplicate_internal(Main *bmain,
const eLibIDDuplicateFlags duplicate_options,
Object **r_ob_new)
{
- Base *base, *basen = nullptr;
- Object *obn;
-
- if (ob->mode & OB_MODE_POSE) {
- /* nothing? */
+ Object *object_new = nullptr;
+ object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new);
+ if (r_ob_new) {
+ *r_ob_new = object_new;
+ }
+ if (object_new == nullptr) {
+ return nullptr;
}
- else {
- obn = static_cast<Object *>(
- ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
- if (r_ob_new) {
- *r_ob_new = obn;
- }
- DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- BKE_view_layer_synced_ensure(scene, view_layer);
- base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != nullptr) && (base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
- BKE_collection_object_add_from(bmain, scene, ob, obn);
- }
- else {
- LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, obn);
- }
-
- BKE_view_layer_synced_ensure(scene, view_layer);
- basen = BKE_view_layer_base_find(view_layer, obn);
- if (base != nullptr && basen != nullptr) {
- basen->local_view_bits = base->local_view_bits;
- }
- /* 1) duplis should end up in same collection as the original
- * 2) Rigid Body sim participants MUST always be part of a collection...
- */
- /* XXX: is 2) really a good measure here? */
- if (ob->rigidbody_object || ob->rigidbody_constraint) {
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- BKE_collection_object_add(bmain, collection, obn);
- }
- }
- }
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Base *base_src = BKE_view_layer_base_find(view_layer, ob);
+ object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new);
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Base *base_new = BKE_view_layer_base_find(view_layer, object_new);
+ if (base_src && base_new) {
+ object_add_sync_local_view(base_src, base_new);
}
- return basen;
+ object_add_sync_rigid_body(bmain, ob, object_new);
+ return base_new;
}
Base *ED_object_add_duplicate(
@@ -3665,70 +3692,70 @@ static int duplicate_exec(bContext *C, wmOperator *op)
* we also want to remap pointers between those... */
BKE_main_id_newptr_and_tag_clear(bmain);
- /* Do not do collection re-syncs for each object; will do it once afterwards.
- * However this means we can't get to new duplicated Base's immediately, will
- * have to process them after the sync. */
- BKE_layer_collection_resync_forbid();
-
/* Duplicate the selected objects, remember data needed to process
- * after the sync (the base of the original object, and the copy of the
- * original object). */
- blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects;
- Object *ob_new_active = nullptr;
+ * after the sync. */
+ struct DuplicateObjectLink {
+ Base *base_src = nullptr;
+ Object *object_new = nullptr;
+
+ DuplicateObjectLink(Base *base_src) : base_src(base_src)
+ {
+ }
+ };
+ blender::Vector<DuplicateObjectLink> object_base_links;
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Object *ob_new = nullptr;
+ object_base_links.append(DuplicateObjectLink(base));
+ }
+ CTX_DATA_END;
+
+ bool new_objects_created = false;
+ for (DuplicateObjectLink &link : object_base_links) {
object_add_duplicate_internal(bmain,
- scene,
- view_layer,
- base->object,
+ link.base_src->object,
dupflag,
LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
- &ob_new);
- if (ob_new == nullptr) {
- continue;
- }
- source_bases_new_objects.append({base, ob_new});
-
- /* note that this is safe to do with this context iterator,
- * the list is made in advance */
- ED_object_base_select(base, BA_DESELECT);
-
- /* new object will become active */
- BKE_view_layer_synced_ensure(scene, view_layer);
- if (BKE_view_layer_active_base_get(view_layer) == base) {
- ob_new_active = ob_new;
+ &link.object_new);
+ if (link.object_new) {
+ new_objects_created = true;
}
}
- CTX_DATA_END;
- BKE_layer_collection_resync_allow();
- if (source_bases_new_objects.is_empty()) {
+ if (!new_objects_created) {
return OPERATOR_CANCELLED;
}
- /* Sync the collection now, after everything is duplicated. */
- BKE_main_collection_sync(bmain);
+ /* Sync that could tag the view_layer out of sync. */
+ for (DuplicateObjectLink &link : object_base_links) {
+ /* note that this is safe to do with this context iterator,
+ * the list is made in advance */
+ ED_object_base_select(link.base_src, BA_DESELECT);
+ if (link.object_new) {
+ object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new);
+ object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new);
+ }
+ }
- /* After sync we can get to the new Base data, process it here. */
- for (const auto &item : source_bases_new_objects) {
- Object *ob_new = item.second;
- Base *base_source = item.first;
- BKE_view_layer_synced_ensure(scene, view_layer);
- Base *base_new = BKE_view_layer_base_find(view_layer, ob_new);
- if (base_new == nullptr) {
+ /* Sync the view layer. Everything else should not tag the view_layer out of sync. */
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ const Base *active_base = BKE_view_layer_active_base_get(view_layer);
+ for (DuplicateObjectLink &link : object_base_links) {
+ if (!link.object_new) {
continue;
}
+
+ Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new);
+ BLI_assert(base_new);
ED_object_base_select(base_new, BA_SELECT);
- if (ob_new == ob_new_active) {
+ if (active_base == link.base_src) {
ED_object_base_activate(C, base_new);
}
- if (base_new->object->data) {
- DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0);
+
+ if (link.object_new->data) {
+ DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0);
}
- /* #object_add_duplicate_internal will not have done this, since
- * before the collection sync it would not have found the new base yet. */
- base_new->local_view_bits = base_source->local_view_bits;
+
+ object_add_sync_local_view(link.base_src, base_new);
}
/* Note that this will also clear newid pointers and tags. */
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 872d2367332..85a35861329 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -21,6 +21,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
@@ -217,7 +218,7 @@ ModifierData *ED_object_modifier_add(
if (ob->mode & OB_MODE_SCULPT) {
/* ensure that grid paint mask layer is created */
- BKE_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md);
+ BKE_sculpt_mask_layers_ensure(nullptr, nullptr, ob, (MultiresModifierData *)new_md);
}
}
else if (type == eModifierType_Skin) {
@@ -788,7 +789,9 @@ static bool modifier_apply_obdata(
if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) {
BKE_report(
- reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers");
+ reports,
+ RPT_ERROR,
+ "Cannot apply constructive modifiers on curve. Convert curve to mesh in order to apply");
return false;
}
@@ -855,8 +858,38 @@ static bool modifier_apply_obdata(
Main *bmain = DEG_get_bmain(depsgraph);
BKE_object_material_from_eval_data(bmain, ob, &curves_eval.id);
}
+ else if (ob->type == OB_POINTCLOUD) {
+ PointCloud &points = *static_cast<PointCloud *>(ob->data);
+ if (mti->modifyGeometrySet == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* Create a temporary geometry set and component. */
+ GeometrySet geometry_set;
+ geometry_set.get_component_for_write<PointCloudComponent>().replace(
+ &points, GeometryOwnershipType::ReadOnly);
+
+ ModifierEvalContext mectx = {depsgraph, ob, (ModifierApplyFlag)0};
+ mti->modifyGeometrySet(md_eval, &mectx, &geometry_set);
+ if (!geometry_set.has_pointcloud()) {
+ BKE_report(
+ reports, RPT_ERROR, "Evaluated geometry from modifier does not contain a point cloud");
+ return false;
+ }
+ PointCloud *pointcloud_eval =
+ geometry_set.get_component_for_write<PointCloudComponent>().release();
+
+ /* Anonymous attributes shouldn't be available on the applied geometry. */
+ pointcloud_eval->attributes_for_write().remove_anonymous();
+
+ /* Copy the relevant information to the original. */
+ Main *bmain = DEG_get_bmain(depsgraph);
+ BKE_object_material_from_eval_data(bmain, ob, &pointcloud_eval->id);
+ BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points, true);
+ }
else {
- /* TODO: implement for point clouds and volumes. */
+ /* TODO: implement for volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -2008,7 +2041,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
if (object->mode & OB_MODE_SCULPT) {
/* ensure that grid paint mask layer is created */
- BKE_sculpt_mask_layers_ensure(object, mmd);
+ BKE_sculpt_mask_layers_ensure(
+ CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C), object, mmd);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 2f18922f4ee..5da19d76259 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2318,26 +2318,39 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
id_root = &collection->id;
user_overrides_from_selected_objects = true;
}
- /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
+ /* Else, poll func ensures us that ID_IS_LINKED(obact) is true, or that it is already an existing
+ * liboverride. */
else {
+ BLI_assert(ID_IS_LINKED(obact) || ID_IS_OVERRIDE_LIBRARY_REAL(obact));
id_root = &obact->id;
user_overrides_from_selected_objects = true;
}
- const bool do_fully_editable = !user_overrides_from_selected_objects;
-
- GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
- BLI_gset_new(BLI_ghashutil_inthash_p,
- BLI_ghashutil_intcmp,
- __func__);
-
/* Make already existing selected liboverrides editable. */
+ bool is_active_override = false;
FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) {
ob_iter->id.override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ is_active_override = is_active_override || (&ob_iter->id == id_root);
+ DEG_id_tag_update(&ob_iter->id, ID_RECALC_COPY_ON_WRITE);
}
}
FOREACH_SELECTED_OBJECT_END;
+ /* If the active object is a liboverride, there is no point going further, since in the weird
+ * case where some other selected objects would be linked ones, there is no way to properly
+ * create overrides for them currently.
+ *
+ * Could be added later if really needed, but would rather avoid that extra complexity here. */
+ if (is_active_override) {
+ return OPERATOR_FINISHED;
+ }
+
+ const bool do_fully_editable = !user_overrides_from_selected_objects;
+
+ GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
+ BLI_gset_new(BLI_ghashutil_inthash_p,
+ BLI_ghashutil_intcmp,
+ __func__);
if (do_fully_editable) {
/* Pass. */
diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc
index a63e06d6866..d874226f04e 100644
--- a/source/blender/editors/object/object_vgroup.cc
+++ b/source/blender/editors/object/object_vgroup.cc
@@ -2376,22 +2376,6 @@ void ED_vgroup_mirror(Object *ob,
/* TODO: vgroup locking.
* TODO: face masking. */
-#define VGROUP_MIRR_OP \
- dvert_mirror_op(dvert, \
- dvert_mirr, \
- sel, \
- sel_mirr, \
- flip_map, \
- flip_map_len, \
- mirror_weights, \
- flip_vgroups, \
- all_vgroups, \
- def_nr)
-
- BMVert *eve, *eve_mirr;
- MDeformVert *dvert_mirr;
- char sel, sel_mirr;
- int *flip_map = nullptr, flip_map_len;
const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
int totmirr = 0, totfail = 0;
@@ -2404,6 +2388,8 @@ void ED_vgroup_mirror(Object *ob,
return;
}
+ int *flip_map = nullptr;
+ int flip_map_len;
if (flip_vgroups) {
flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) :
BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len);
@@ -2438,21 +2424,27 @@ void ED_vgroup_mirror(Object *ob,
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
/* Go through the list of edit-vertices and assign them. */
+ BMVert *eve, *eve_mirr;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
if (eve_mirr != eve) {
if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
- sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
- sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
+ const bool sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ const bool sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
if ((sel || sel_mirr) && (eve != eve_mirr)) {
- MDeformVert *dvert = static_cast<MDeformVert *>(
- BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
- dvert_mirr = static_cast<MDeformVert *>(
- BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(
+ static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)),
+ static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)),
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
@@ -2471,39 +2463,38 @@ void ED_vgroup_mirror(Object *ob,
}
else {
/* object mode / weight paint */
- int vidx, vidx_mirr;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->deform_verts().is_empty()) {
goto cleanup;
}
- if (!use_vert_sel) {
- sel = sel_mirr = true;
- }
-
BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false);
- for (vidx = 0; vidx < me->totvert; vidx++) {
+ for (int vidx = 0; vidx < me->totvert; vidx++) {
if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
+ int vidx_mirr;
if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) {
if (vidx != vidx_mirr) {
if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
-
- if (use_vert_sel) {
- sel = select_vert[vidx];
- sel_mirr = select_vert[vidx_mirr];
- }
+ const bool sel = use_vert_sel ? select_vert[vidx] : true;
+ const bool sel_mirr = use_vert_sel ? select_vert[vidx_mirr] : true;
if (sel || sel_mirr) {
- MDeformVert *dvert = &dverts[vidx];
- dvert_mirr = &dvert[vidx_mirr];
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(&dverts[vidx],
+ &dverts[vidx_mirr],
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
@@ -2523,9 +2514,6 @@ void ED_vgroup_mirror(Object *ob,
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = vgroup_edit_lattice(ob);
- int i1, i2;
- int u, v, w;
- int pntsu_half;
/* half but found up odd value */
if (lt->pntsu == 1 || lt->dvert == nullptr) {
@@ -2535,29 +2523,33 @@ void ED_vgroup_mirror(Object *ob,
/* unlike editmesh we know that by only looping over the first half of
* the 'u' indices it will cover all points except the middle which is
* ok in this case */
- pntsu_half = lt->pntsu / 2;
+ int pntsu_half = lt->pntsu / 2;
- for (w = 0; w < lt->pntsw; w++) {
- for (v = 0; v < lt->pntsv; v++) {
- for (u = 0; u < pntsu_half; u++) {
+ for (int w = 0; w < lt->pntsw; w++) {
+ for (int v = 0; v < lt->pntsv; v++) {
+ for (int u = 0; u < pntsu_half; u++) {
int u_inv = (lt->pntsu - 1) - u;
if (u != u_inv) {
- BPoint *bp, *bp_mirr;
+ const int i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
+ const int i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
- i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
- i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
+ const BPoint *bp = &lt->def[i1];
+ const BPoint *bp_mirr = &lt->def[i2];
- bp = &lt->def[i1];
- bp_mirr = &lt->def[i2];
-
- sel = bp->f1 & SELECT;
- sel_mirr = bp_mirr->f1 & SELECT;
+ const bool sel = bp->f1 & SELECT;
+ const bool sel_mirr = bp_mirr->f1 & SELECT;
if (sel || sel_mirr) {
- MDeformVert *dvert = &lt->dvert[i1];
- dvert_mirr = &lt->dvert[i2];
-
- VGROUP_MIRR_OP;
+ dvert_mirror_op(&lt->dvert[i1],
+ &lt->dvert[i2],
+ sel,
+ sel_mirr,
+ flip_map,
+ flip_map_len,
+ mirror_weights,
+ flip_vgroups,
+ all_vgroups,
+ def_nr);
totmirr++;
}
}
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 1ce90849a88..41238eb171b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -405,7 +405,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* primary output layer */
if (surface->flags & MOD_DPAINT_OUT1) {
/* set filepath */
- BLI_join_dirfile(
+ BLI_path_join(
filepath, sizeof(filepath), surface->image_output_path, surface->output_name);
BLI_path_frame(filepath, frame, 4);
@@ -415,7 +415,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* secondary output */
if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
/* set filepath */
- BLI_join_dirfile(
+ BLI_path_join(
filepath, sizeof(filepath), surface->image_output_path, surface->output_name2);
BLI_path_frame(filepath, frame, 4);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 761a6702c6f..e6d0aca7902 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -3533,7 +3533,7 @@ static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagg
}
const bool use_dm_final_indices = (psys->part->use_modifier_stack &&
- !psmd_eval->mesh_final->runtime.deformed_only);
+ !BKE_mesh_is_deformed_only(psmd_eval->mesh_final));
/* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
BKE_mesh_tessface_ensure(me);
@@ -4353,7 +4353,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
0,
0,
0)) {
- if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
+ if (psys->part->use_modifier_stack && !BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) {
add_pars[iter].num = add_pars[iter].num_dmcache;
add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
}
@@ -4430,7 +4430,7 @@ static int brush_add(const bContext *C, PEData *data, short number)
timestep = psys_get_timestep(&sim);
- if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
+ if (psys->part->use_modifier_stack || BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) {
mesh = psmd_eval->mesh_final;
}
else {
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 08db03db0e9..210757173eb 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -732,7 +732,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(to_imat, to_mat);
const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
- !target_psmd->mesh_final->runtime.deformed_only);
+ !BKE_mesh_is_deformed_only(target_psmd->mesh_final));
if (use_dm_final_indices || !target_psmd->mesh_original) {
mesh = target_psmd->mesh_final;
@@ -1204,9 +1204,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
#undef PSYS_FROM_FIRST
#undef PSYS_FROM_NEXT
- if (duplicate_settings) {
- DEG_relations_tag_update(bmain);
- }
+ DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob_to->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
return true;
@@ -1269,8 +1267,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
if (changed_tot > 0) {
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- DEG_graph_tag_relations_update(depsgraph);
+ DEG_relations_tag_update(CTX_data_main(C));
}
if ((changed_tot == 0 && fail == 0) || fail) {
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 07e8f5c5743..314796e96e4 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -368,7 +368,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
BKE_spacedata_draw_locks(true);
if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
@@ -376,7 +376,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_noise;
}
if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
@@ -384,8 +384,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_mesh;
}
if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_abs(temp_dir, relbase);
/* Create 'particles' subdir if it does not exist already */
@@ -396,7 +395,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_particles;
}
if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
@@ -404,11 +403,11 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_guide;
}
if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
@@ -416,8 +415,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
job->pause_frame = &fds->cache_frame_pause_data;
if (fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index ad24f46f923..140199209da 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -1325,7 +1325,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
const char *brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
/* Expected to be found, but don't crash if it's not. */
if (brushicons_dir) {
- BLI_join_dirfile(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath);
+ BLI_path_join(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath);
/* Use default color spaces. */
brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc
index 25d5ceb8216..83ce447e8cf 100644
--- a/source/blender/editors/render/render_shading.cc
+++ b/source/blender/editors/render/render_shading.cc
@@ -879,7 +879,7 @@ static int new_world_exec(bContext *C, wmOperator * /*op*/)
wo = new_wo;
}
else {
- wo = BKE_world_add(bmain, DATA_("World"));
+ wo = BKE_world_add(bmain, CTX_DATA_(BLT_I18NCONTEXT_ID_WORLD, "World"));
ED_node_shader_default(C, &wo->id);
wo->use_nodes = true;
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index f19017cb723..01877deb716 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -286,6 +286,7 @@ static void SCENE_OT_new(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", "");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_SCENE);
}
/** \} */
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 39e3c7a2f0a..8db968cbb8a 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -187,7 +187,8 @@ static void area_draw_azone_fullscreen(
min_ff(alpha, 0.75f),
0.0f,
NULL,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/**
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 9a6bdc98d76..8cf11583b3a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -405,7 +405,7 @@ static WorkspaceConfigFileData *workspace_config_file_read(const char *app_templ
char startup_file_path[FILE_MAX] = {0};
if (cfgdir) {
- BLI_join_dirfile(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE);
+ BLI_path_join(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE);
}
bool has_path = BLI_exists(startup_file_path);
@@ -425,8 +425,7 @@ static WorkspaceConfigFileData *workspace_system_file_read(const char *app_templ
}
char startup_file_path[FILE_MAX];
- BLI_join_dirfile(
- startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE);
+ BLI_path_join(startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE);
bool has_path = BLI_exists(startup_file_path);
return (has_path) ? BKE_blendfile_workspace_config_read(startup_file_path, NULL, 0, NULL) : NULL;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 79316361e53..b7ce4b2973c 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -402,7 +402,8 @@ static ImBuf *brush_painter_imbuf_new(
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ const MTex *mtex = &brush->mtex;
+ BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
@@ -446,6 +447,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ const MTex *mtex = &brush->mtex;
BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
@@ -485,7 +487,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
if (!use_texture_old) {
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
+ BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index ced7949c69f..d5c5aa5cebd 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -74,11 +74,8 @@ class AbstractPaintMode {
class ImagePaintMode : public AbstractPaintMode {
public:
- void *paint_new_stroke(bContext *C,
- wmOperator *op,
- Object * /*ob*/,
- const float UNUSED(mouse[2]),
- int mode) override
+ void *paint_new_stroke(
+ bContext *C, wmOperator *op, Object * /*ob*/, const float /*mouse*/[2], int mode) override
{
return paint_2d_new_stroke(C, op, mode);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 8ffa78cd457..d9aa11a2847 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -4074,7 +4074,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->totloop_eval = ps->me_eval->totloop;
ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
- ps->totlooptri_eval = ps->me_eval->runtime.looptris.len;
+ ps->totlooptri_eval = BKE_mesh_runtime_looptri_len(ps->me_eval);
ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
@@ -5370,7 +5370,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
/* Color texture (alpha used as mask). */
if (ps->is_texbrush) {
- MTex *mtex = &brush->mtex;
+ const MTex *mtex = BKE_brush_color_texture_get(brush, OB_MODE_TEXTURE_PAINT);
float samplecos[3];
float texrgba[4];
@@ -5386,7 +5386,8 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
/* NOTE: for clone and smear,
* we only use the alpha, could be a special function */
- BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
+ BKE_brush_sample_tex_3d(
+ ps->scene, brush, mtex, samplecos, texrgba, thread_index, pool);
copy_v3_v3(texrgb, texrgba);
custom_mask *= texrgba[3];
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index e1fd731a4b7..571ebd79764 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -31,6 +31,7 @@
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
@@ -146,7 +147,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
value = RNA_float_get(op->ptr, "value");
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false);
pbvh = ob->sculpt->pbvh;
@@ -861,7 +862,9 @@ static void sculpt_gesture_mask_end(bContext *C, SculptGestureContext *sgcontext
BKE_pbvh_update_vertex_data(sgcontext->ss->pbvh, PBVH_UpdateMask);
}
-static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, wmOperator *op)
+static void sculpt_gesture_init_mask_properties(bContext *C,
+ SculptGestureContext *sgcontext,
+ wmOperator *op)
{
sgcontext->operation = MEM_callocN(sizeof(SculptGestureMaskOperation), "Mask Operation");
@@ -869,7 +872,8 @@ static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext,
Object *object = sgcontext->vc.obact;
MultiresModifierData *mmd = BKE_sculpt_multires_active(sgcontext->vc.scene, object);
- BKE_sculpt_mask_layers_ensure(sgcontext->vc.obact, mmd);
+ BKE_sculpt_mask_layers_ensure(
+ CTX_data_depsgraph_pointer(C), CTX_data_main(C), sgcontext->vc.obact, mmd);
mask_operation->op.sculpt_gesture_begin = sculpt_gesture_mask_begin;
mask_operation->op.sculpt_gesture_apply_for_symmetry_pass =
@@ -1514,7 +1518,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
@@ -1526,7 +1530,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
@@ -1538,7 +1542,7 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op)
if (!sgcontext) {
return OPERATOR_CANCELLED;
}
- sculpt_gesture_init_mask_properties(sgcontext, op);
+ sculpt_gesture_init_mask_properties(C, sgcontext, op);
sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index cb981a3bfb1..ce4a5151a20 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -286,7 +286,7 @@ static void imapaint_pick_uv(
const ePaintCanvasSource mode = scene->toolsettings->imapaint.mode;
const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
- const int tottri = me_eval->runtime.looptris.len;
+ const int tottri = BKE_mesh_runtime_looptri_len(me_eval);
const MVert *mvert = BKE_mesh_verts(me_eval);
const MLoop *mloop = BKE_mesh_loops(me_eval);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 6e3504332ed..acd8b1a6bb1 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -433,9 +433,10 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp,
float r_rgba[4])
{
const Brush *brush = BKE_paint_brush(&vp->paint);
- BLI_assert(brush->mtex.tex != nullptr);
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr);
+ const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
+ BLI_assert(mtex->tex != nullptr);
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr);
}
else {
float co_ss[2]; /* screenspace */
@@ -445,7 +446,7 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp,
co_ss,
(eV3DProjTest)(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR)) == V3D_PROJ_RET_OK) {
const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
- BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr);
+ BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr);
}
else {
zero_v4(r_rgba);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9e1b1cda0c3..95192114429 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -41,6 +41,7 @@
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
@@ -1981,7 +1982,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
int(*orco_tris)[3];
int orco_tris_num;
- BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
+ BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, NULL);
for (int i = 0; i < orco_tris_num; i++) {
const float *co_tri[3] = {
@@ -2457,7 +2458,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
- const MTex *mtex = &br->mtex;
+ const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT);
float avg = 1.0f;
float rgba[4];
float point[3];
@@ -2469,7 +2470,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex location directly into a texture. */
- avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
+ avg = BKE_brush_sample_tex_3d(scene, br, mtex, point, rgba, 0, ss->tex_pool);
}
else {
float symm_point[3], point_2d[2];
@@ -2498,19 +2499,19 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
x = symm_point[0];
y = symm_point[1];
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
+ x *= mtex->size[0];
+ y *= mtex->size[1];
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
+ x += mtex->ofs[0];
+ y += mtex->ofs[1];
- avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
+ avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id);
avg += br->texture_sample_bias;
}
else {
const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
- avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool);
+ avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool);
}
}
@@ -3265,7 +3266,7 @@ static void sculpt_topology_update(Sculpt *sd,
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_node_mark_topology_update(nodes[n]);
- BKE_pbvh_bmesh_node_save_orig(ss->bm, nodes[n]);
+ BKE_pbvh_bmesh_node_save_orig(ss->bm, ss->bm_log, nodes[n], false);
}
}
@@ -4272,7 +4273,8 @@ static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ ToolSettings *tool_settings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
@@ -4407,6 +4409,13 @@ static void sculpt_update_cache_invariants(
}
}
+ /* Original coordinates require the sculpt undo system, which isn't used
+ * for image brushes. It's also not necessary, just disable it. */
+ if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
+ SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
+ cache->original = false;
+ }
+
cache->first_time = true;
#define PIXEL_INPUT_THRESHHOLD 5
@@ -5658,7 +5667,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
}
if (SCULPT_tool_is_mask(brush->sculpt_tool)) {
MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);
}
if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) {
Mesh *mesh = BKE_object_get_original_mesh(ob);
@@ -5749,15 +5758,14 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent
if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
/* Did the stroke never start? If so push a blank sculpt undo
* step to prevent a global undo step (which is triggered by the
- * OPTYPE_UNDO flag in SCULPT_OT_brush_stroke).
+ * #OPTYPE_UNDO flag in #SCULPT_OT_brush_stroke).
*
* Having blank global undo steps interleaved with sculpt steps
* corrupts the DynTopo undo stack.
* See T101430.
*
- * Note: simply returning OPERATOR_CANCELLED was not
- * sufficient to prevent this.
- */
+ * NOTE: simply returning #OPERATOR_CANCELLED was not
+ * sufficient to prevent this. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index 5a0fcd8bc27..505440c9272 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -503,7 +503,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
PBVHVertRef vert,
AutomaskingNodeData *automask_data)
{
- if (!automasking) {
+ if (!automasking || vert.i == PBVH_REF_NONE) {
return 1.0f;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 041efbb357c..92541d10a59 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -2149,6 +2149,8 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float final_disp[3];
switch (brush->elastic_deform_type) {
case BRUSH_ELASTIC_DEFORM_GRAB:
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 90279cb339c..3133bb2007e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -27,6 +27,7 @@
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "DEG_depsgraph.h"
@@ -166,15 +167,16 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
if (expand_cache->texture_distortion_strength == 0.0f) {
return expand_cache->vert_falloff[v_i];
}
-
- if (!expand_cache->brush->mtex.tex) {
+ const Brush *brush = expand_cache->brush;
+ const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
+ if (!mtex->tex) {
return expand_cache->vert_falloff[v_i];
}
float rgba[4];
const float *vertex_co = SCULPT_vertex_co_get(ss, v);
const float avg = BKE_brush_sample_tex_3d(
- expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool);
+ expand_cache->scene, brush, mtex, vertex_co, rgba, 0, ss->tex_pool);
const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength *
expand_cache->max_vert_falloff;
@@ -2107,6 +2109,11 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
+ if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+ }
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, needs_colors);
/* Do nothing when the mesh has 0 vertices. */
@@ -2121,11 +2128,6 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
}
- if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
- }
-
/* Face Set operations are not supported in dyntopo. */
if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS &&
BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
index 15a91e4eaab..8fb4dea668e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
@@ -18,6 +18,7 @@
#include "BLI_math_vector.hh"
#include "BLI_span.hh"
#include "BLI_task.h"
+#include "BLI_task.hh"
#include "DNA_brush_types.h"
#include "DNA_customdata_types.h"
@@ -198,8 +199,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
/* This operations needs a strength tweak as the relax deformation is too weak by default. */
- if (relax_face_sets) {
- bstrength *= 2.0f;
+ if (relax_face_sets && data->iteration < 2) {
+ bstrength *= 1.5f;
}
const int thread_id = BLI_task_parallel_thread_id(tls);
@@ -261,6 +262,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
if (ss->cache->alt_smooth) {
SCULPT_boundary_info_ensure(ob);
for (int i = 0; i < 4; i++) {
+ data.iteration = i;
BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
}
}
@@ -312,6 +314,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
{
+ using namespace blender;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -395,25 +398,16 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
if (mode == SCULPT_FACE_SET_SELECTION) {
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- BMeshCreateParams create_params{};
- create_params.use_toolflags = true;
- bm = BM_mesh_create(&allocsize, &create_params);
-
- BMeshFromMeshParams convert_params{};
- convert_params.calc_vert_normal = true;
- convert_params.calc_face_normal = true;
- BM_mesh_bm_from_me(bm, mesh, &convert_params);
-
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- ss->face_sets[BM_elem_index_get(f)] = next_face_set;
+ const bke::AttributeAccessor attributes = mesh->attributes();
+ const VArraySpan<bool> select_poly = attributes.lookup_or_default<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE, false);
+ threading::parallel_for(IndexRange(mesh->totvert), 4096, [&](const IndexRange range) {
+ for (const int i : range) {
+ if (select_poly[i]) {
+ ss->face_sets[i] = next_face_set;
+ }
}
- }
- BM_mesh_free(bm);
+ });
}
for (int i = 0; i < totnode; i++) {
@@ -827,9 +821,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
const int tot_vert = SCULPT_vertex_count_get(ss);
- const int active_face_set = SCULPT_active_face_set_get(ss);
-
- SCULPT_undo_push_begin(ob, op);
PBVH *pbvh = ob->sculpt->pbvh;
PBVHNode **nodes;
@@ -842,62 +833,86 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
- bool hidden_vertex = false;
+ const int active_face_set = SCULPT_active_face_set_get(ss);
- /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
- * be synced from face sets to non-manifold vertices. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+ SCULPT_undo_push_begin(ob, op);
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_HIDDEN);
+ }
- if (!SCULPT_vertex_visible_get(ss, vertex)) {
- hidden_vertex = true;
- break;
+ switch (mode) {
+ case SCULPT_FACE_SET_VISIBILITY_TOGGLE: {
+ bool hidden_vertex = false;
+
+ /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
+ * be synced from face sets to non-manifold vertices. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ for (int i = 0; i < tot_vert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
+ hidden_vertex = true;
+ break;
+ }
}
}
- }
- if (ss->hide_poly) {
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->hide_poly[i]) {
- hidden_vertex = true;
- break;
+ if (ss->hide_poly) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->hide_poly[i]) {
+ hidden_vertex = true;
+ break;
+ }
}
}
- }
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (hidden_vertex) {
- SCULPT_face_visibility_all_set(ss, true);
- }
- else {
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ if (hidden_vertex) {
+ SCULPT_face_visibility_all_set(ss, true);
+ }
+ else {
+ if (ss->face_sets) {
+ SCULPT_face_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ else {
+ SCULPT_face_visibility_all_set(ss, true);
+ }
+ }
+ break;
}
- }
+ case SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
+ if (ss->face_sets) {
+ SCULPT_face_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ else {
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ break;
+ case SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_set_visibility_set(ss, active_face_set, false);
- }
+ if (ss->face_sets) {
+ SCULPT_face_set_visibility_set(ss, active_face_set, false);
+ }
+ else {
+ SCULPT_face_visibility_all_set(ss, false);
+ }
- if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_invert(ss);
+ break;
+ case SCULPT_FACE_SET_VISIBILITY_INVERT:
+ ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
+ SCULPT_face_visibility_all_invert(ss);
+ break;
}
/* For modes that use the cursor active vertex, update the rotation origin for viewport
- * navigation. */
+ * navigation.
+ */
if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
float location[3];
@@ -912,7 +927,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
SCULPT_visibility_sync_all_from_faces(ob);
SCULPT_undo_push_end(ob);
-
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 69eac9a6168..8e199a72858 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -16,6 +16,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -166,7 +167,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int filter_type = RNA_enum_get(op->ptr, "filter_type");
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index edb681466b5..bf47b64d176 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -332,7 +332,7 @@ typedef struct SculptThreadedTaskData {
int mask_init_seed;
ThreadMutex mutex;
-
+ int iteration;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 56ddb99fe28..1b8cc5347ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -14,6 +14,7 @@
#include "DNA_brush_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_ccg.h"
@@ -331,6 +332,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SculptCursorGeometryInfo sgi;
const float mval_fl[2] = {UNPACK2(event->mval)};
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
SCULPT_vertex_random_access_ensure(ss);
op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position");
@@ -338,8 +344,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
int vertex_count = SCULPT_vertex_count_get(ss);
ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
index 5d7ef9aab15..99a7bb8a926 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
@@ -15,6 +15,7 @@
#include "DNA_brush_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_ccg.h"
@@ -110,6 +111,9 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
PBVH *pbvh = ob->sculpt->pbvh;
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 1042356489b..a740ec2773b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -21,6 +21,7 @@
#include "DNA_listBase.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -1041,12 +1042,12 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
+ BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
SCULPT_vertex_random_access_ensure(ss);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
-
SCULPT_undo_push_begin(ob, op);
CavityBakeMixMode mode = RNA_enum_get(op->ptr, "mix_mode");
@@ -1116,10 +1117,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
-
- /* Unlike other operators we do not tag the ID for update here;
- * it triggers a PBVH rebuild which is too slow and ruins
- * the interactivity of the tool. */
+ SCULPT_tag_update_overlays(C);
return OPERATOR_FINISHED;
}
@@ -1294,11 +1292,10 @@ static int sculpt_reveal_all_exec(bContext *C, wmOperator *op)
SCULPT_visibility_sync_all_from_faces(ob);
- /* Note: SCULPT_visibility_sync_all_from_faces may have deleted
- * pbvh->hide_vert if hide_poly did not exist, which is why
- * we call BKE_pbvh_update_hide_attributes_from_mesh here instead of
- * after CustomData_free_layer_named above.
- */
+ /* NOTE: #SCULPT_visibility_sync_all_from_faces may have deleted
+ * `pbvh->hide_vert` if hide_poly did not exist, which is why
+ * we call #BKE_pbvh_update_hide_attributes_from_mesh here instead of
+ * after #CustomData_free_layer_named above. */
if (!with_bmesh) {
BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh);
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index f276c2acd1a..486f9f9ccb0 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -201,7 +201,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_property_collection_lookup_int(op->ptr, prop, 0, &fileptr);
RNA_string_get(&fileptr, "name", file_only);
- BLI_join_dirfile(str, sizeof(str), dir_only, file_only);
+ BLI_path_join(str, sizeof(str), dir_only, file_only);
}
else {
BKE_report(op->reports, RPT_ERROR, "No files selected to be opened");
@@ -1611,7 +1611,9 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
ot->poll = ED_space_clip_poll;
/* properties */
- RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
+ ot->prop = RNA_def_enum(
+ ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
}
/** \} */
@@ -1639,14 +1641,14 @@ static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
float pan_vec[3];
const wmNDOFMotionData *ndof = event->customdata;
- const float speed = NDOF_PIXELS_PER_SECOND;
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, (speed * ndof->dt) / sc->zoom);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ mul_v2_fl(pan_vec, pan_speed / sc->zoom);
- sclip_zoom_set_factor(C, 1.0f + pan_vec[2], NULL, false);
+ sclip_zoom_set_factor(C, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false);
sc->xof += pan_vec[0];
sc->yof += pan_vec[1];
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 554b628ba0f..240901318b5 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -410,8 +410,15 @@ static void file_draw_preview(const SpaceFile *sfile,
}
icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f));
- UI_icon_draw_ex(
- icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ icon,
+ icon_aspect / U.dpi_fac,
+ icon_opacity,
+ 0.0f,
+ icon_color,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
if (is_link || is_offline) {
@@ -424,8 +431,24 @@ static void file_draw_preview(const SpaceFile *sfile,
/* At very bottom-left if preview style. */
const uchar dark[4] = {0, 0, 0, 255};
const uchar light[4] = {255, 255, 255, 255};
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1,
+ icon_y - 1,
+ arrow,
+ 1.0f / U.dpi_fac,
+ 0.2f,
+ 0.0f,
+ dark,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ arrow,
+ 1.0f / U.dpi_fac,
+ 0.6f,
+ 0.0f,
+ light,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
else {
/* Link to folder or non-previewed file. */
@@ -433,8 +456,15 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_GetThemeColor4ubv(TH_BACK, icon_color);
icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx;
icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy;
- UI_icon_draw_ex(
- icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ arrow,
+ icon_aspect / U.dpi_fac * 1.8,
+ 0.3f,
+ 0.0f,
+ icon_color,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
}
else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) {
@@ -444,8 +474,17 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + (2.0f * UI_DPI_FAC);
icon_y = yco + (2.0f * UI_DPI_FAC);
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1,
+ icon_y - 1,
+ icon,
+ 1.0f / U.dpi_fac,
+ 0.2f,
+ 0.0f,
+ dark,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT);
}
const bool is_current_main_data = filelist_file_get_id(file) != NULL;
@@ -456,7 +495,15 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + ex - UI_UNIT_X;
icon_y = yco + ey - UI_UNIT_Y;
- UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x,
+ icon_y,
+ ICON_CURRENT_FILE,
+ 1.0f / U.dpi_fac,
+ 0.6f,
+ 0.0f,
+ light,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/* Contrasting outline around some preview types. */
@@ -544,10 +591,10 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
ARegion *region = CTX_wm_region(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
- BLI_join_dirfile(orgname, sizeof(orgname), params->dir, oldname);
+ BLI_path_join(orgname, sizeof(orgname), params->dir, oldname);
BLI_strncpy(filename, params->renamefile, sizeof(filename));
BLI_filename_make_safe(filename);
- BLI_join_dirfile(newname, sizeof(newname), params->dir, filename);
+ BLI_path_join(newname, sizeof(newname), params->dir, filename);
if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
@@ -952,7 +999,7 @@ void file_draw_list(const bContext *C, ARegion *region)
file = filelist_file(files, i);
file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
- BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+ BLI_path_join(path, sizeof(path), root, file->relpath);
if (!(file_selflag & FILE_SEL_EDITING)) {
if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ||
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index f7fd910d6e9..a4d4bf98474 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -386,7 +386,7 @@ static bool fsmenu_write_file_and_refresh_or_report_error(struct FSMenu *fsmenu,
}
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE);
if (UNLIKELY(!fsmenu_write_file(fsmenu, filepath))) {
BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath);
return false;
@@ -1564,7 +1564,7 @@ void file_sfile_to_operator_ex(
PropertyRNA *prop;
/* XXX, not real length */
- BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file);
+ BLI_path_join(filepath, FILE_MAX, params->dir, params->file);
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (RNA_property_boolean_get(op->ptr, prop)) {
@@ -1741,7 +1741,7 @@ bool file_draw_check_exists(SpaceFile *sfile)
const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params && (params->flag & FILE_CHECK_EXISTING)) {
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file);
+ BLI_path_join(filepath, sizeof(filepath), params->dir, params->file);
if (BLI_is_file(filepath)) {
return true;
}
@@ -2311,13 +2311,13 @@ static bool new_folder_path(const char *parent, char folder[FILE_MAX], char name
int len = 0;
BLI_strncpy(name, "New Folder", FILE_MAXFILE);
- BLI_join_dirfile(folder, FILE_MAX, parent, name);
+ BLI_path_join(folder, FILE_MAX, parent, name);
/* check whether folder with the name already exists, in this case
* add number to the name. Check length of generated name to avoid
* crazy case of huge number of folders each named 'New Folder (x)' */
while (BLI_exists(folder) && (len < FILE_MAXFILE)) {
len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
- BLI_join_dirfile(folder, FILE_MAX, parent, name);
+ BLI_path_join(folder, FILE_MAX, parent, name);
i++;
}
@@ -2457,8 +2457,7 @@ static void file_expand_directory(bContext *C)
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr));
- BLI_path_join(
- params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr, NULL);
+ BLI_path_join(params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr);
}
else if (params->dir[0] == '\0')
@@ -2622,7 +2621,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
- BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file);
+ BLI_path_join(filepath, sizeof(params->dir), params->dir, params->file);
/* if directory, open it and empty filename field */
if (filelist_is_dir(sfile->files, filepath)) {
@@ -2850,7 +2849,7 @@ static bool file_delete_single(const FileSelectParams *params,
const char **r_error_message)
{
char str[FILE_MAX];
- BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath);
+ BLI_path_join(str, sizeof(str), params->dir, file->relpath);
if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) {
return false;
}
diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc
index c2dc8e9196d..f177eebf6f2 100644
--- a/source/blender/editors/space_file/filelist.cc
+++ b/source/blender/editors/space_file/filelist.cc
@@ -115,6 +115,9 @@ struct FileListInternEntry {
* Owning pointer. */
AssetMetaData *imported_asset_data;
+ /* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
+ bool blenderlib_has_no_preview;
+
/** Defined in BLI_fileops.h */
eFileAttributes attributes;
BLI_stat_t st;
@@ -844,7 +847,7 @@ static bool is_filtered_lib_type(FileListInternEntry *file,
{
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
- BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+ BLI_path_join(path, sizeof(path), root, file->relpath);
if (BLO_library_path_explode(path, dir, &group, &name)) {
return is_filtered_id_file_type(file, group, name, filter);
@@ -1204,7 +1207,7 @@ static int filelist_geticon_ex(const FileDirEntry *file,
target = file->redirection_path;
}
else if (root) {
- BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_path_join(fullpath, sizeof(fullpath), root, file->relpath);
BLI_path_slash_ensure(fullpath);
}
for (; tfsm; tfsm = tfsm->next) {
@@ -1575,6 +1578,14 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
+ /* If we know this is an external ID without a preview, skip loading the preview. Can save quite
+ * some time in heavy files, because otherwise for each missing preview and for each preview
+ * reload, we'd reopen the .blend to look for the preview. */
+ if ((entry->typeflag & FILE_TYPE_BLENDERLIB) &&
+ (entry->flags & FILE_ENTRY_BLENDERLIB_NO_PREVIEW)) {
+ return;
+ }
+
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
@@ -1606,7 +1617,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR);
}
else {
- BLI_join_dirfile(
+ BLI_path_join(
preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath);
}
// printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
@@ -1894,7 +1905,7 @@ static char *fileentry_uiname(const char *root,
if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
char abspath[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
+ BLI_path_join(abspath, sizeof(abspath), root, relpath);
name = BLF_display_name_from_file(abspath);
if (name) {
/* Allocated string, so no need to #BLI_strdup. */
@@ -1906,7 +1917,7 @@ static char *fileentry_uiname(const char *root,
char abspath[FILE_MAX_LIBEXTRA];
char *group;
- BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
+ BLI_path_join(abspath, sizeof(abspath), root, relpath);
BLO_library_path_explode(abspath, buff, &group, &name);
if (!name) {
name = group;
@@ -2042,6 +2053,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
}
}
+ if (entry->blenderlib_has_no_preview) {
+ ret->flags |= FILE_ENTRY_BLENDERLIB_NO_PREVIEW;
+ }
BLI_addtail(&cache->cached_entries, ret);
return ret;
}
@@ -2887,7 +2901,7 @@ static int filelist_readjob_list_dir(const char *root,
entry->relpath = static_cast<char *>(MEM_dupallocN(files[i].relname));
entry->st = files[i].s;
- BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
+ BLI_path_join(full_path, FILE_MAX, root, entry->relpath);
char *target = full_path;
/* Set initial file type and attributes. */
@@ -2995,10 +3009,15 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
entry->relpath = BLI_strdup(datablock_info->name);
}
entry->typeflag |= FILE_TYPE_BLENDERLIB;
- if (datablock_info && datablock_info->asset_data) {
- entry->typeflag |= FILE_TYPE_ASSET;
- /* Moves ownership! */
- entry->imported_asset_data = datablock_info->asset_data;
+
+ if (datablock_info) {
+ entry->blenderlib_has_no_preview = datablock_info->no_preview_found;
+
+ if (datablock_info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = datablock_info->asset_data;
+ }
}
entry->blentype = idcode;
BLI_addtail(entries, entry);
@@ -3525,7 +3544,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
/* When loading entries recursive, the rel_path should be relative from the root dir.
* we combine the relative path to the subdir with the relative path of the entry. */
- BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath);
+ BLI_path_join(dir, sizeof(dir), rel_subdir, entry->relpath);
MEM_freeN(entry->relpath);
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
@@ -3535,7 +3554,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
if (filelist_readjob_should_recurse_into_entry(
max_recursion, is_lib, recursion_level, entry)) {
/* We have a directory we want to list, add it to todo list! */
- BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
+ BLI_path_join(dir, sizeof(dir), root, entry->relpath);
BLI_path_normalize_dir(job_params->main_name, dir);
td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs));
td_dir->level = recursion_level + 1;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 9ebc4872544..df7e9702e85 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1174,7 +1174,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
char path[FILE_MAX];
BLI_stat_t status;
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+ BLI_path_join(path, sizeof(path), dirname, de->d_name);
if (BLI_stat(path, &status) == 0) {
if (S_ISDIR(status.st_mode)) { /* is subdir */
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 35ce7ef364c..cea53908d4f 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -113,10 +113,10 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home)
char filepath[FILE_MAX];
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home != NULL) {
- BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs", NULL);
+ BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs");
}
else {
- BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs", NULL);
+ BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs");
}
fp = BLI_fopen(filepath, "r");
if (!fp) {
@@ -147,7 +147,7 @@ static GHash *fsmenu_xdg_user_dirs_parse(const char *home)
* Based on the 'user-dirs.dirs' man page,
* there is no need to resolve arbitrary environment variables. */
if (STRPREFIX(l_value, "$HOME" SEP_STR)) {
- BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6, NULL);
+ BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6);
l_value_final = l_value_expanded;
}
@@ -186,7 +186,7 @@ static void fsmenu_xdg_insert_entry(GHash *xdg_map,
char xdg_path_buf[FILE_MAXDIR];
const char *xdg_path = xdg_map ? BLI_ghash_lookup(xdg_map, key) : NULL;
if (xdg_path == NULL) {
- BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path, NULL);
+ BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path);
xdg_path = xdg_path_buf;
}
fsmenu_insert_entry(
@@ -254,10 +254,10 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL;
- BLI_join_dirfile(tmp_name,
- sizeof(tmp_name),
- BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
- BLENDER_BOOKMARK_FILE);
+ BLI_path_join(tmp_name,
+ sizeof(tmp_name),
+ BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
}
@@ -318,10 +318,10 @@ void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
BLI_strncpy(fsentry->name, name, sizeof(fsentry->name));
}
- BLI_join_dirfile(tmp_name,
- sizeof(tmp_name),
- BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
- BLENDER_BOOKMARK_FILE);
+ BLI_path_join(tmp_name,
+ sizeof(tmp_name),
+ BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
}
@@ -983,7 +983,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (xdg_runtime_dir != NULL) {
struct direntry *dirs;
char name[FILE_MAX];
- BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/");
+ BLI_path_join(name, sizeof(name), xdg_runtime_dir, "gvfs/");
const uint dirs_num = BLI_filelist_dir_contents(name, &dirs);
for (uint i = 0; i < dirs_num; i++) {
if (dirs[i].type & S_IFDIR) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index a3182222263..74f1b8e838a 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -1157,7 +1157,7 @@ void ED_file_read_bookmarks(void)
if (cfgdir) {
char name[FILE_MAX];
- BLI_join_dirfile(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE);
+ BLI_path_join(name, sizeof(name), cfgdir, BLENDER_BOOKMARK_FILE);
fsmenu_read_bookmarks(ED_fsmenu_get(), name);
}
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 42ebed6ec3a..85b1e2b6707 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -589,15 +589,27 @@ void ED_space_image_grid_steps(SpaceImage *sima,
float grid_steps_y[SI_GRID_STEPS_LEN],
const int grid_dimension)
{
- const int flag = sima->flag;
+ const eSpaceImage_GridShapeSource grid_shape_source = sima->grid_shape_source;
for (int step = 0; step < SI_GRID_STEPS_LEN; step++) {
- if (flag & SI_CUSTOM_GRID) {
- grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0];
- grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1];
- }
- else {
- grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
- grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ switch (grid_shape_source) {
+ case SI_GRID_SHAPE_DYNAMIC:
+ grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN);
+ break;
+ case SI_GRID_SHAPE_FIXED:
+ grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0];
+ grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1];
+ break;
+ case SI_GRID_SHAPE_PIXEL: {
+ int pixel_width = IMG_SIZE_FALLBACK;
+ int pixel_height = IMG_SIZE_FALLBACK;
+ ED_space_image_get_size(sima, &pixel_width, &pixel_height);
+ BLI_assert(pixel_width > 0 && pixel_height > 0);
+ grid_steps_x[step] = 1.0f / pixel_width;
+ grid_steps_y[step] = 1.0f / pixel_height;
+ } break;
+ default:
+ BLI_assert_unreachable();
}
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index bb47ad5c6c0..3503c4c8168 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -762,14 +762,14 @@ static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
float pan_vec[3];
const wmNDOFMotionData *ndof = event->customdata;
- const float speed = NDOF_PIXELS_PER_SECOND;
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ mul_v2_fl(pan_vec, pan_speed / sima->zoom);
- sima_zoom_set_factor(sima, region, 1.0f + pan_vec[2], NULL, false);
+ sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false);
sima->xof += pan_vec[0];
sima->yof += pan_vec[1];
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 7108c258665..d2725652979 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -62,14 +62,14 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
STREQLEN(base_tail, tail, FILE_MAX)) {
/* Set filepath to first frame in the range. */
if (frame->framenr < range_first_frame) {
- BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename);
range_first_frame = frame->framenr;
}
}
else {
/* start a new frame range */
range = MEM_callocN(sizeof(*range), __func__);
- BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ BLI_path_join(range->filepath, sizeof(range->filepath), dir, filename);
BLI_addtail(ranges, range);
BLI_strncpy(base_head, head, sizeof(base_head));
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 71cbcea1c1f..53e1bc0a1e5 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -5,6 +5,7 @@
* \ingroup spimage
*/
+#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
#include "DNA_image_types.h"
#include "DNA_mask_types.h"
@@ -117,6 +118,8 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED(
simage->custom_grid_subdiv[0] = 10;
simage->custom_grid_subdiv[1] = 10;
+ simage->mask_info = *DNA_struct_default_get(MaskSpaceInfo);
+
/* header */
region = MEM_callocN(sizeof(ARegion), "header for image");
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index cac0dbb0067..e8b005b2b67 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -40,6 +40,7 @@
#include "BKE_key.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -94,8 +95,8 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
int totvert, totedge, totface, totloop;
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
- const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+ const SubdivCCG *subdiv_ccg = me_eval->runtime->subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime->subsurf_runtime_data;
if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index aee72860a0a..12ee6f45991 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -235,7 +235,8 @@ static bool textview_draw_string(TextViewDrawState *tds,
1.0f,
0.0f,
icon_fg,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 9df25b1229e..8a3c6745259 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -2641,6 +2641,8 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
void NLA_OT_fmodifier_add(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add F-Modifier";
ot->idname = "NLA_OT_fmodifier_add";
@@ -2659,11 +2661,12 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION);
RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf);
- RNA_def_boolean(ot->srna,
- "only_active",
- true,
- "Only Active",
- "Only add a F-Modifier of the specified type to the active strip");
+ prop = RNA_def_boolean(ot->srna,
+ "only_active",
+ true,
+ "Only Active",
+ "Only add a F-Modifier of the specified type to the active strip");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION);
}
/** \} */
@@ -2832,8 +2835,10 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(
+ ot->prop = RNA_def_boolean(
ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip");
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION);
+
RNA_def_boolean(
ot->srna,
"replace",
diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc
index 819f0abac7c..28e18c20f46 100644
--- a/source/blender/editors/space_node/add_node_search.cc
+++ b/source/blender/editors/space_node/add_node_search.cc
@@ -182,6 +182,9 @@ static void gather_add_node_operations(const bContext &C,
/* Skip the empty group type. */
continue;
}
+ if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) {
+ continue;
+ }
AddNodeItem item{};
item.ui_name = IFACE_(node_type->ui_name);
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index 17410937d4c..ffa2d377056 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -274,7 +274,9 @@ static void gather_socket_link_operations(const bContext &C,
if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
continue;
}
-
+ if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) {
+ continue;
+ }
if (node_type->gather_link_search_ops) {
nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
node_type->gather_link_search_ops(params);
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index dc155f5e28d..98b2cacd162 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -2145,6 +2145,9 @@ static void node_draw_basis(const bContext &C,
0,
"");
UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
+ if (node.id) {
+ UI_but_icon_indicator_number_set(but, node.id->us);
+ }
UI_block_emboss_set(&block, UI_EMBOSS);
}
if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
@@ -3011,7 +3014,7 @@ static void node_draw_nodetree(const bContext &C,
}
}
-/* Draw the breadcrumb on the bottom of the editor. */
+/* Draw the breadcrumb on the top of the editor. */
static void draw_tree_path(const bContext &C, ARegion &region)
{
using namespace blender;
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 3a80733f06c..48b3d711bdf 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -1361,12 +1361,15 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
+ bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0);
+ const bool dupli_node_tree = !linked;
bool changed = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
Map<const bNode *, bNode *> node_map;
Map<const bNodeSocket *, bNodeSocket *> socket_map;
+ Map<const ID *, ID *> duplicated_node_groups;
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -1374,6 +1377,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
bNode *new_node = bke::node_copy_with_mapping(
ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, new_node);
+
+ if (node->id && dupli_node_tree) {
+ ID *new_group = duplicated_node_groups.lookup_or_add_cb(node->id, [&]() {
+ ID *new_group = BKE_id_copy(bmain, node->id);
+ /* Remove user added by copying. */
+ id_us_min(new_group);
+ return new_group;
+ });
+ id_us_plus(new_group);
+ id_us_min(new_node->id);
+ new_node->id = new_group;
+ }
changed = true;
}
@@ -1462,6 +1477,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
void NODE_OT_duplicate(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Duplicate Nodes";
ot->description = "Duplicate selected nodes";
@@ -1476,6 +1493,13 @@ void NODE_OT_duplicate(wmOperatorType *ot)
RNA_def_boolean(
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
+
+ prop = RNA_def_boolean(ot->srna,
+ "linked",
+ true,
+ "Linked",
+ "Duplicate node but not node trees, linking to the original data");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* XXX: some code needing updating to operators. */
@@ -2275,6 +2299,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator * /*op*/)
newlink->tosock = socket_map.lookup(link->tosock);
newlink->fromnode = node_map.lookup(link->fromnode);
newlink->fromsock = socket_map.lookup(link->fromsock);
+ newlink->multi_input_socket_index = link->multi_input_socket_index;
BKE_node_clipboard_add_link(newlink);
}
@@ -2396,11 +2421,19 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
- nodeAddLink(ntree,
- node_map.lookup(link->fromnode),
- socket_map.lookup(link->fromsock),
- node_map.lookup(link->tonode),
- socket_map.lookup(link->tosock));
+ bNodeLink *new_link = nodeAddLink(ntree,
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
+ new_link->multi_input_socket_index = link->multi_input_socket_index;
+ }
+
+ ntree->ensure_topology_cache();
+
+ for (bNode *new_node : node_map.values()) {
+ /* Update multi input socket indices in case all connected nodes weren't copied. */
+ update_multi_input_indices_for_removed_links(*new_node);
}
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 50c03489027..1c3026628a6 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -270,6 +270,8 @@ void NODE_OT_group_edit(wmOperatorType *ot);
/* node_relationships.cc */
+void update_multi_input_indices_for_removed_links(bNode &node);
+
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
void NODE_OT_links_cut(wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index 6c52dae5b86..d45c33a3c59 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -174,7 +174,17 @@ void ED_operatormacros_node()
"Duplicate",
"Duplicate selected nodes and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
- WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ RNA_boolean_set(mot->ptr, "linked", false);
+ WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
+
+ ot = WM_operatortype_append_macro(
+ "NODE_OT_duplicate_move_linked",
+ "Duplicate Linked",
+ "Duplicate selected nodes, but not their node trees, and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
+ RNA_boolean_set(mot->ptr, "linked", true);
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
/* modified operator call for duplicating with input links */
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 7cf18e2f828..637c795d4d7 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -64,6 +64,10 @@ struct NodeInsertOfsData {
float offset_x; /* offset to apply to node chain */
};
+namespace blender::ed::space_node {
+
+bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out);
+
static void clear_picking_highlight(ListBase *links)
{
LISTBASE_FOREACH (bNodeLink *, link, links) {
@@ -71,10 +75,6 @@ static void clear_picking_highlight(ListBase *links)
}
}
-namespace blender::ed::space_node {
-
-void update_multi_input_indices_for_removed_links(bNode &node);
-
/* -------------------------------------------------------------------- */
/** \name Add Node
* \{ */
@@ -815,7 +815,8 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/,
nldrag->cursor[0];
const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
- UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+ UI_icon_draw_ex(
+ x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT);
}
static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
@@ -1750,29 +1751,31 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e
}
LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
- if (node->flag & NODE_SELECT) {
- if (node->parent == nullptr) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- /* attach all unparented nodes */
- nodeAttachNode(node, frame);
- }
+ if (!(node->flag & NODE_SELECT)) {
+ continue;
+ }
+
+ if (node->parent == nullptr) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ /* attach all unparented nodes */
+ nodeAttachNode(node, frame);
}
- else {
- /* attach nodes which share parent with the frame */
- bNode *parent;
- for (parent = frame->parent; parent; parent = parent->parent) {
- if (parent == node->parent) {
- break;
- }
+ }
+ else {
+ /* attach nodes which share parent with the frame */
+ bNode *parent;
+ for (parent = frame->parent; parent; parent = parent->parent) {
+ if (parent == node->parent) {
+ break;
}
+ }
- if (parent) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- nodeDetachNode(node);
- nodeAttachNode(node, frame);
- }
+ if (parent) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ nodeDetachNode(node);
+ nodeAttachNode(node, frame);
}
}
}
@@ -1881,100 +1884,55 @@ void NODE_OT_detach(wmOperatorType *ot)
/** \name Automatic Node Insert on Dragging
* \{ */
-/* prevent duplicate testing code below */
-static bool ed_node_link_conditions(ScrArea *area,
- bool test,
- SpaceNode **r_snode,
- bNode **r_select)
+static bNode *get_selected_node_for_insertion(bNodeTree &node_tree)
{
- SpaceNode *snode = area ? (SpaceNode *)area->spacedata.first : nullptr;
-
- *r_snode = snode;
- *r_select = nullptr;
-
- /* no unlucky accidents */
- if (area == nullptr || area->spacetype != SPACE_NODE) {
- return false;
- }
-
- if (!test) {
- /* no need to look for a node */
- return true;
- }
-
- bNode *node;
- bNode *select = nullptr;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ bNode *selected_node = nullptr;
+ int selected_node_count = 0;
+ for (bNode *node : node_tree.all_nodes()) {
if (node->flag & SELECT) {
- if (select) {
- break;
- }
- select = node;
+ selected_node = node;
+ selected_node_count++;
+ }
+ if (selected_node_count > 1) {
+ return nullptr;
}
}
- /* only one selected */
- if (node || select == nullptr) {
- return false;
+ if (!selected_node) {
+ return nullptr;
}
-
- /* correct node */
- if (BLI_listbase_is_empty(&select->inputs) || BLI_listbase_is_empty(&select->outputs)) {
- return false;
+ if (selected_node->input_sockets().is_empty() || selected_node->output_sockets().is_empty()) {
+ return nullptr;
}
-
- ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
-
- /* test node for links */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
- continue;
- }
-
- if (link->tonode == select || link->fromnode == select) {
- return false;
- }
+ if (std::any_of(selected_node->input_sockets().begin(),
+ selected_node->input_sockets().end(),
+ [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) {
+ return nullptr;
}
-
- *r_select = select;
- return true;
+ if (std::any_of(selected_node->output_sockets().begin(),
+ selected_node->output_sockets().end(),
+ [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) {
+ return nullptr;
+ };
+ return selected_node;
}
-/** \} */
-
-} // namespace blender::ed::space_node
-
-/* -------------------------------------------------------------------- */
-/** \name Node Line Intersection Test
- * \{ */
-
-void ED_node_link_intersect_test(ScrArea *area, int test)
+void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region)
{
- using namespace blender;
- using namespace blender::ed::space_node;
-
- bNode *select;
- SpaceNode *snode;
- if (!ed_node_link_conditions(area, test, &snode, &select)) {
- return;
- }
+ bNodeTree &node_tree = *snode.edittree;
+ node_tree.ensure_topology_cache();
- /* clear flags */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- link->flag &= ~NODE_LINKFLAG_HILITE;
- }
+ node_insert_on_link_flags_clear(node_tree);
- if (test == 0) {
+ bNode *node_to_insert = get_selected_node_for_insertion(node_tree);
+ if (!node_to_insert) {
return;
}
- ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
-
/* find link to select/highlight */
bNodeLink *selink = nullptr;
float dist_best = FLT_MAX;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
-
- if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
@@ -1986,10 +1944,10 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
* upper left node edge of a intersected line segment */
for (int i = 0; i < NODE_LINK_RESOL; i++) {
/* Check if the node rectangle intersects the line from this point to next one. */
- if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) {
+ if (BLI_rctf_isect_segment(&node_to_insert->totr, coords[i], coords[i + 1])) {
/* store the shortest distance to the upper left edge
* of all intersections found so far */
- const float node_xy[] = {select->totr.xmin, select->totr.ymax};
+ const float node_xy[] = {node_to_insert->totr.xmin, node_to_insert->totr.ymax};
/* to be precise coords should be clipped by select->totr,
* but not done since there's no real noticeable difference */
@@ -2009,9 +1967,89 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
-/** \} */
+void node_insert_on_link_flags_clear(bNodeTree &node_tree)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
+ link->flag &= ~NODE_LINKFLAG_HILITE;
+ }
+}
-namespace blender::ed::space_node {
+void node_insert_on_link_flags(Main &bmain, SpaceNode &snode)
+{
+ bNodeTree &node_tree = *snode.edittree;
+ node_tree.ensure_topology_cache();
+ bNode *node_to_insert = get_selected_node_for_insertion(node_tree);
+ if (!node_to_insert) {
+ return;
+ }
+
+ /* Find link to insert on. */
+ bNodeTree &ntree = *snode.edittree;
+ bNodeLink *old_link = nullptr;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (link->flag & NODE_LINKFLAG_HILITE) {
+ old_link = link;
+ break;
+ }
+ }
+ if (old_link == nullptr) {
+ return;
+ }
+
+ old_link->flag &= ~NODE_LINKFLAG_HILITE;
+
+ bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN);
+ bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT);
+
+ if (node_to_insert->type != NODE_REROUTE) {
+ /* Ignore main sockets when the types don't match. */
+ if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr &&
+ !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type),
+ static_cast<eNodeSocketDatatype>(best_input->type))) {
+ best_input = nullptr;
+ }
+ if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr &&
+ !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type),
+ static_cast<eNodeSocketDatatype>(old_link->tosock->type))) {
+ best_output = nullptr;
+ }
+ }
+
+ bNode *from_node = old_link->fromnode;
+ bNodeSocket *from_socket = old_link->fromsock;
+ bNode *to_node = old_link->tonode;
+
+ if (best_output != nullptr) {
+ /* Relink the "start" of the existing link to the newly inserted node. */
+ old_link->fromnode = node_to_insert;
+ old_link->fromsock = best_output;
+ BKE_ntree_update_tag_link_changed(&ntree);
+ }
+ else {
+ nodeRemLink(&ntree, old_link);
+ }
+
+ if (best_input != nullptr) {
+ /* Add a new link that connects the node on the left to the newly inserted node. */
+ nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input);
+ }
+
+ /* Set up insert offset data, it needs stuff from here. */
+ if ((snode.flag & SNODE_SKIP_INSOFFSET) == 0) {
+ BLI_assert(snode.runtime->iofsd == nullptr);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
+
+ iofsd->insert = node_to_insert;
+ iofsd->prev = from_node;
+ iofsd->next = to_node;
+
+ snode.runtime->iofsd = iofsd;
+ }
+
+ ED_node_tree_propagate_change(nullptr, &bmain, &ntree);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Insert Offset Operator
@@ -2048,7 +2086,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
}
/** Get the "main" socket based on the node declaration or an heuristic. */
-static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
+bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
{
ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
@@ -2426,85 +2464,3 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \} */
} // namespace blender::ed::space_node
-
-/* -------------------------------------------------------------------- */
-/** \name Note Link Insert
- * \{ */
-
-void ED_node_link_insert(Main *bmain, ScrArea *area)
-{
- using namespace blender::ed::space_node;
-
- bNode *node_to_insert;
- SpaceNode *snode;
- if (!ed_node_link_conditions(area, true, &snode, &node_to_insert)) {
- return;
- }
-
- /* Find link to insert on. */
- bNodeTree &ntree = *snode->edittree;
- bNodeLink *old_link = nullptr;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (link->flag & NODE_LINKFLAG_HILITE) {
- old_link = link;
- break;
- }
- }
- if (old_link == nullptr) {
- return;
- }
-
- old_link->flag &= ~NODE_LINKFLAG_HILITE;
-
- bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN);
- bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT);
-
- if (node_to_insert->type != NODE_REROUTE) {
- /* Ignore main sockets when the types don't match. */
- if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr &&
- !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type),
- static_cast<eNodeSocketDatatype>(best_input->type))) {
- best_input = nullptr;
- }
- if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr &&
- !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type),
- static_cast<eNodeSocketDatatype>(old_link->tosock->type))) {
- best_output = nullptr;
- }
- }
-
- bNode *from_node = old_link->fromnode;
- bNodeSocket *from_socket = old_link->fromsock;
- bNode *to_node = old_link->tonode;
-
- if (best_output != nullptr) {
- /* Relink the "start" of the existing link to the newly inserted node. */
- old_link->fromnode = node_to_insert;
- old_link->fromsock = best_output;
- BKE_ntree_update_tag_link_changed(&ntree);
- }
- else {
- nodeRemLink(&ntree, old_link);
- }
-
- if (best_input != nullptr) {
- /* Add a new link that connects the node on the left to the newly inserted node. */
- nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input);
- }
-
- /* Set up insert offset data, it needs stuff from here. */
- if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- BLI_assert(snode->runtime->iofsd == nullptr);
- NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
-
- iofsd->insert = node_to_insert;
- iofsd->prev = from_node;
- iofsd->next = to_node;
-
- snode->runtime->iofsd = iofsd;
- }
-
- ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
-}
-
-/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index 259d879d76f..3b07c6da5fa 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -888,7 +888,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static char *datastack_drop_tooltip(bContext * /*C*/,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
struct wmDropBox * /*drop*/)
{
StackDropData *drop_data = static_cast<StackDropData *>(drag->poin);
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 8a1119d5e66..699dd6d4844 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -2877,7 +2877,8 @@ static bool tselem_draw_icon(uiBlock *block,
TreeStoreElem *tselem,
TreeElement *te,
float alpha,
- const bool is_clickable)
+ const bool is_clickable,
+ const int num_elements)
{
TreeElementIcon data = tree_element_get_icon(tselem, te);
if (data.icon == 0) {
@@ -2885,6 +2886,8 @@ static bool tselem_draw_icon(uiBlock *block,
}
const bool is_collection = outliner_is_collection_tree_element(te);
+ IconTextOverlay text_overlay;
+ UI_icon_text_overlay_init_from_count(&text_overlay, num_elements);
/* Collection colors and icons covered by restrict buttons. */
if (!is_clickable || x >= xmax || is_collection) {
@@ -2904,7 +2907,8 @@ static bool tselem_draw_icon(uiBlock *block,
alpha,
0.0f,
btheme->collection_color[collection->color_tag].color,
- true);
+ true,
+ &text_overlay);
return true;
}
}
@@ -2915,10 +2919,10 @@ static bool tselem_draw_icon(uiBlock *block,
/* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */
uchar color[4];
if (UI_icon_get_theme_color(data.icon, color)) {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay);
}
else {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay);
}
}
else {
@@ -2941,53 +2945,6 @@ static bool tselem_draw_icon(uiBlock *block,
return true;
}
-/**
- * For icon-only children of a collapsed tree,
- * Draw small number over the icon to show how many items of this type are displayed.
- */
-static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
- int offsx,
- int ys,
- const int num_elements)
-{
- const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float ufac = 0.25f * UI_UNIT_X;
- float offset_x = float(offsx) + UI_UNIT_X * 0.35f;
- rctf rect{};
- BLI_rctf_init(&rect,
- offset_x + ufac,
- offset_x + UI_UNIT_X - ufac,
- float(ys) - UI_UNIT_Y * 0.2f + ufac,
- float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(&rect, true, float(UI_UNIT_Y) / 2.0f - ufac, color);
-
- /* Now the numbers. */
- uchar text_col[4];
-
- UI_GetThemeColor3ubv(TH_TEXT_HI, text_col);
- text_col[3] = 255;
-
- uiFontStyle fstyle_small = *fstyle;
- fstyle_small.points *= 0.8f;
-
- /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
- int num_digits = 4;
- char number_text[4] = "+99";
- if (num_elements < 100) {
- BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
- num_digits = num_elements < 10 ? 1 : 2;
- }
- UI_fontstyle_draw_simple(&fstyle_small,
- (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f),
- float(ys) - UI_UNIT_Y * 0.095f + ufac,
- number_text,
- text_col);
- UI_fontstyle_set(fstyle);
- GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */
-}
-
static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
{
float text[4];
@@ -3020,7 +2977,6 @@ static void outliner_draw_active_indicator(const float minx,
static void outliner_draw_iconrow_doit(uiBlock *block,
TreeElement *te,
- const uiFontStyle *fstyle,
int xmax,
int *offsx,
int ys,
@@ -3049,13 +3005,13 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
if (tselem->flag & TSE_HIGHLIGHTED_ICON) {
alpha_fac += 0.5;
}
- tselem_draw_icon(block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false);
+ tselem_draw_icon(
+ block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements);
te->xs = *offsx;
te->ys = ys;
te->xend = short(*offsx) + UI_UNIT_X;
if (num_elements > 1) {
- outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
te->flag |= TE_ICONROW_MERGED;
}
else {
@@ -3098,6 +3054,7 @@ static void outliner_draw_iconrow(bContext *C,
int *offsx,
int ys,
float alpha_fac,
+ bool in_bone_hierarchy,
MergedIconRow *merged)
{
eOLDrawState active = OL_DRAWSEL_NONE;
@@ -3107,8 +3064,12 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
+ /* Bones are also hierarchies and get a merged count, but we only start recursing into them if
+ * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed
+ * collection). */
+ const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL);
if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
- ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) {
+ (in_bone_hierarchy && is_bone)) {
/* active blocks get white circle */
if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
@@ -3139,7 +3100,7 @@ static void outliner_draw_iconrow(bContext *C,
TSE_POSE_CHANNEL,
TSE_POSEGRP,
TSE_DEFGROUP)) {
- outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
+ outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
const int index = tree_element_id_type_to_index(te);
@@ -3151,8 +3112,13 @@ static void outliner_draw_iconrow(bContext *C,
}
}
- /* this tree element always has same amount of branches, so don't draw */
- if (tselem->type != TSE_R_LAYER) {
+ /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */
+ /* Also only recurse into bone hierarchies if a direct child of the collapsed element to merge
+ * into. */
+ const bool is_root_level_bone = is_bone && (level == 0);
+ in_bone_hierarchy |= is_root_level_bone;
+ if (!ELEM(tselem->type, TSE_R_LAYER, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL) ||
+ in_bone_hierarchy) {
outliner_draw_iconrow(C,
block,
fstyle,
@@ -3164,6 +3130,7 @@ static void outliner_draw_iconrow(bContext *C,
offsx,
ys,
alpha_fac,
+ in_bone_hierarchy,
merged);
}
}
@@ -3181,7 +3148,6 @@ static void outliner_draw_iconrow(bContext *C,
if (merged->num_elements[index] != 0) {
outliner_draw_iconrow_doit(block,
merged->tree_element[index],
- fstyle,
xmax,
offsx,
ys,
@@ -3370,7 +3336,8 @@ static void outliner_draw_tree_element(bContext *C,
tselem,
te,
(tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
- true)) {
+ true,
+ 1)) {
offsx += UI_UNIT_X + 4 * ufac;
}
else {
@@ -3425,6 +3392,7 @@ static void outliner_draw_tree_element(bContext *C,
&tempx,
*starty,
alpha_fac,
+ false,
&merged);
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index 6eca6fffece..9a6a25fdbae 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -809,7 +809,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
@@ -843,7 +843,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
char str[FILE_MAX];
const short flag = FILE_AUTOSELECT | FILE_ACTIVE_COLLECTION;
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, 0);
if (num_pasted == 0) {
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 6ef8d7fd108..b17d0bfac4e 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -274,7 +274,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
BLI_strncpy(load_data->name, filename, sizeof(load_data->name));
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename);
+ BLI_path_join(load_data->path, sizeof(load_data->path), directory, filename);
MEM_freeN(filename);
break;
}
@@ -834,7 +834,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
+ BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
@@ -1082,7 +1082,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
char file_only[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir_only);
RNA_string_get(&itemptr, "name", file_only);
- BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
+ BLI_path_join(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
if (seq == NULL) {
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 201425dafab..a6916f9d031 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -804,7 +804,7 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc
switch (seq->type) {
case SEQ_TYPE_IMAGE:
case SEQ_TYPE_MOVIE: {
- BLI_join_dirfile(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(r_source, source_len, seq->strip->dir, seq->strip->stripdata->name);
break;
}
case SEQ_TYPE_SOUND_RAM: {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 2938513f130..c0c7782c60c 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2939,7 +2939,7 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
Sequence *seq = SEQ_select_active_get(scene);
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_join(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name);
RNA_string_set(op->ptr, "directory", seq->strip->dir);
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 8b6d37caa41..1d20926d16c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -129,7 +129,6 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
region->flag = RGN_FLAG_HIDDEN;
- region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
/* Channels. */
region = MEM_callocN(sizeof(ARegion), "channels for sequencer");
@@ -137,6 +136,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_CHANNELS;
region->alignment = RGN_ALIGN_LEFT;
+ region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
/* Preview region. */
/* NOTE: if you change values here, also change them in sequencer_init_preview_region. */
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index 46e98acb8e8..af41225f42a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -12,6 +12,7 @@
#include "BLI_string_ref.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "spreadsheet_column.hh"
#include "spreadsheet_column_values.hh"
@@ -44,7 +45,7 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<std::string>()) {
return SPREADSHEET_VALUE_TYPE_STRING;
}
- if (type.is<InstanceReference>()) {
+ if (type.is<bke::InstanceReference>()) {
return SPREADSHEET_VALUE_TYPE_INSTANCES;
}
if (type.is<ColorGeometry4b>()) {
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 8af12590b0f..59a8daf4f4a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -10,6 +10,7 @@
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
#include "BKE_global.h"
+#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -143,29 +144,31 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
- if (STREQ(column_id.name, "Name")) {
- Span<int> reference_handles = instances.instance_reference_handles();
- Span<InstanceReference> references = instances.references();
- return std::make_unique<ColumnValues>(
- column_id.name,
- VArray<InstanceReference>::ForFunc(domain_num,
- [reference_handles, references](int64_t index) {
- return references[reference_handles[index]];
- }));
- }
- Span<float4x4> transforms = instances.instance_transforms();
- if (STREQ(column_id.name, "Rotation")) {
- return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
- return transforms[index].to_euler();
- }));
- }
- if (STREQ(column_id.name, "Scale")) {
- return std::make_unique<ColumnValues>(
- column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
- return transforms[index].scale();
- }));
+ if (const bke::Instances *instances =
+ static_cast<const InstancesComponent &>(*component_).get_for_read()) {
+ if (STREQ(column_id.name, "Name")) {
+ Span<int> reference_handles = instances->reference_handles();
+ Span<bke::InstanceReference> references = instances->references();
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<bke::InstanceReference>::ForFunc(
+ domain_num, [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
+ }
+ Span<float4x4> transforms = instances->transforms();
+ if (STREQ(column_id.name, "Rotation")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
+ }
+ if (STREQ(column_id.name, "Scale")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_num, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
}
}
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
@@ -487,37 +490,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
return geometry_set;
}
-class GeometryComponentCacheKey : public SpreadsheetCache::Key {
- public:
- /* Use the pointer to the geometry component as a key to detect when the geometry changed. */
- const GeometryComponent *component;
-
- GeometryComponentCacheKey(const GeometryComponent &component) : component(&component)
- {
- }
-
- uint64_t hash() const override
- {
- return get_default_hash(this->component);
- }
-
- bool is_equal_to(const Key &other) const override
- {
- if (const GeometryComponentCacheKey *other_geo =
- dynamic_cast<const GeometryComponentCacheKey *>(&other)) {
- return this->component == other_geo->component;
- }
- return false;
- }
-};
-
-class GeometryComponentCacheValue : public SpreadsheetCache::Value {
- public:
- /* Stores the result of fields evaluated on a geometry component. Without this, fields would have
- * to be reevaluated on every redraw. */
- Map<std::pair<eAttrDomain, GField>, GArray<>> arrays;
-};
-
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index b4b8417c172..06eb338bd00 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -6,6 +6,7 @@
#include "BLI_math_vec_types.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
@@ -197,10 +198,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
this->draw_byte_color(params, value);
}
- else if (data.type().is<InstanceReference>()) {
- const InstanceReference value = data.get<InstanceReference>(real_index);
+ else if (data.type().is<bke::InstanceReference>()) {
+ const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
switch (value.type()) {
- case InstanceReference::Type::Object: {
+ case bke::InstanceReference::Type::Object: {
const Object &object = value.object();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -219,7 +220,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::Collection: {
+ case bke::InstanceReference::Type::Collection: {
Collection &collection = value.collection();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -238,7 +239,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::GeometrySet: {
+ case bke::InstanceReference::Type::GeometrySet: {
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
@@ -256,7 +257,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
break;
}
- case InstanceReference::Type::None: {
+ case bke::InstanceReference::Type::None: {
break;
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 96827692a25..3586389b00b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -14,6 +14,8 @@
#include "RNA_access.h"
+#include "BKE_instances.hh"
+
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
@@ -280,22 +282,22 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
- else if (column_data.type().is<InstanceReference>()) {
+ else if (column_data.type().is<bke::InstanceReference>()) {
const StringRef value = row_filter.value_string;
apply_filter_operation(
- column_data.typed<InstanceReference>(),
- [&](const InstanceReference cell) {
+ column_data.typed<bke::InstanceReference>(),
+ [&](const bke::InstanceReference cell) {
switch (cell.type()) {
- case InstanceReference::Type::Object: {
+ case bke::InstanceReference::Type::Object: {
return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
}
- case InstanceReference::Type::Collection: {
+ case bke::InstanceReference::Type::Collection: {
return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
}
- case InstanceReference::Type::GeometrySet: {
+ case bke::InstanceReference::Type::GeometrySet: {
return false;
}
- case InstanceReference::Type::None: {
+ case bke::InstanceReference::Type::None: {
return false;
}
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 36ced74a8b7..6370d56ae8c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -17,6 +17,7 @@
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -94,8 +95,8 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
const MPoly *mp;
int i;
- if (me->runtime.looptris.array) {
- const MLoopTri *mlt = me->runtime.looptris.array;
+ if (BKE_mesh_runtime_looptri_ensure(me)) {
+ const MLoopTri *mlt = BKE_mesh_runtime_looptri_ensure(me);
for (mp = polys, i = 0; i < mpoly_len; i++, mp++) {
if (facemap_data[i] == facemap) {
for (int j = 2; j < mp->totloop; j++) {
diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc
index 4ac6f926818..635fbd75d74 100644
--- a/source/blender/editors/space_view3d/space_view3d.cc
+++ b/source/blender/editors/space_view3d/space_view3d.cc
@@ -631,7 +631,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven
static char *view3d_object_data_drop_tooltip(bContext * /*C*/,
wmDrag * /*drag*/,
- const int UNUSED(xy[2]),
+ const int /*xy*/[2],
wmDropBox * /*drop*/)
{
return BLI_strdup(TIP_("Create object instance from object-data"));
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
index c61eac3c777..793ada4f577 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc
@@ -19,8 +19,10 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -234,8 +236,8 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
Object *ob = gz_ele->bases[gz_ele->base_index]->object;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, static_cast<ID *>(ob->data));
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
+ if (me_eval->runtime->edit_data) {
+ coords = me_eval->runtime->edit_data->vertexCos;
}
}
EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc
index 139ac9de6e4..932563863fe 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.cc
+++ b/source/blender/editors/space_view3d/view3d_iterators.cc
@@ -262,7 +262,7 @@ struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenObjectVert_userData *data = static_cast<foreachScreenObjectVert_userData *>(
userData);
@@ -316,7 +316,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenVert_userData *data = static_cast<foreachScreenVert_userData *>(userData);
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
@@ -538,7 +538,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
static void mesh_foreachScreenFace__mapFunc(void *userData,
int index,
const float cent[3],
- const float UNUSED(no[3]))
+ const float /*no*/[3])
{
foreachScreenFace_userData *data = static_cast<foreachScreenFace_userData *>(userData);
BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
@@ -576,7 +576,7 @@ void mesh_foreachScreenFace(
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
- if (me->runtime.subsurf_face_dot_tags != nullptr) {
+ if (me->runtime->subsurf_face_dot_tags != nullptr) {
BKE_mesh_foreach_mapped_subdiv_face_center(
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
index 29e63a72daf..9fb33013c4e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_ndof.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
@@ -370,14 +370,17 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
+ const float pan_speed = NDOF_PIXELS_PER_SECOND;
const bool has_translate = !is_zero_v2(ndof->tvec);
const bool has_zoom = ndof->tvec[2] != 0.0f;
float pan_vec[3];
WM_event_ndof_pan_get(ndof, pan_vec, true);
- mul_v2_fl(pan_vec, ndof->dt);
- pan_vec[2] *= -ndof->dt;
+ mul_v3_fl(pan_vec, ndof->dt);
+ /* NOTE: unlike image and clip views, the 2D pan doesn't have to be scaled by the zoom level.
+ * #ED_view3d_camera_view_pan already takes the zoom level into account. */
+ mul_v2_fl(pan_vec, pan_speed);
/* NOTE(@campbellbarton): In principle rotating could pass through to regular
* non-camera NDOF behavior (exiting the camera-view and rotating).
@@ -393,16 +396,14 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
bool changed = false;
if (has_translate) {
- const float speed = NDOF_PIXELS_PER_SECOND;
- float event_ofs[2] = {pan_vec[0] * speed, pan_vec[1] * speed};
- if (ED_view3d_camera_view_pan(region, event_ofs)) {
+ /* Use the X & Y of `pan_vec`. */
+ if (ED_view3d_camera_view_pan(region, pan_vec)) {
changed = true;
}
}
if (has_zoom) {
- const float scale = 1.0f + pan_vec[2];
- if (ED_view3d_camera_view_zoom_scale(rv3d, scale)) {
+ if (ED_view3d_camera_view_zoom_scale(rv3d, max_ff(0.0f, 1.0f - pan_vec[2]))) {
changed = true;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 3e0ce892b5a..fcb4f549353 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -849,11 +849,15 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event)
if (ret) {
WalkTeleport *teleport = &walk->teleport;
+
+ /* Store the current navigation mode if we are not already teleporting. */
+ if (teleport->state == WALK_TELEPORT_STATE_OFF) {
+ teleport->navigation_mode = walk->navigation_mode;
+ }
teleport->state = WALK_TELEPORT_STATE_ON;
teleport->initial_time = PIL_check_seconds_timer();
teleport->duration = U.walk_navigation.teleport_time;
- teleport->navigation_mode = walk->navigation_mode;
walk_navigation_mode_set(walk, WALK_MODE_FREE);
copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
@@ -864,9 +868,7 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event)
sub_v3_v3v3(teleport->direction, loc, teleport->origin);
}
- else {
- walk->teleport.state = WALK_TELEPORT_STATE_OFF;
- }
+
break;
}
@@ -1229,11 +1231,11 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* keep moving if we were moving */
copy_v2_v2(dvec, walk->teleport.direction);
- z_cur = walk->rv3d->viewinv[3][2];
- z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid;
+ z_cur = walk->rv3d->viewinv[3][2] / walk->grid;
+ z_new = (walk->teleport.origin[2] / walk->grid) - getFreeFallDistance(walk->gravity, t);
/* jump */
- z_new += t * walk->speed_jump * walk->grid;
+ z_new += t * walk->speed_jump;
/* duration is the jump duration */
if (t > walk->teleport.duration) {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 6fbd553e17b..ad12aef6d67 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -59,7 +59,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied);
@@ -91,7 +91,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
flag |= FILE_ACTIVE_COLLECTION;
}
- BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
+ BLI_path_join(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, FILTER_ID_OB);
if (num_pasted == 0) {
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index ec6f62e0f5b..3787a59c83c 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -40,7 +40,7 @@ set(SRC
transform_convert_mesh_uv.c
transform_convert_mesh_vert_cdata.c
transform_convert_nla.c
- transform_convert_node.c
+ transform_convert_node.cc
transform_convert_object.c
transform_convert_object_texspace.c
transform_convert_paintcurve.c
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 6f7eb317b42..5b194ae7237 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -60,8 +60,6 @@
* and being able to set it to zero is handy. */
/* #define USE_NUM_NO_ZERO */
-static void initSnapSpatial(TransInfo *t, float r_snap[2]);
-
bool transdata_check_local_islands(TransInfo *t, short around)
{
if (t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) {
@@ -1518,26 +1516,26 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- bool use_prop_edit = false;
- int prop_edit_flag = 0;
- if (t->flag & T_PROP_EDIT_ALL) {
- if (t->flag & T_PROP_EDIT) {
- use_prop_edit = true;
- }
- if (t->flag & T_PROP_CONNECTED) {
- prop_edit_flag |= PROP_EDIT_CONNECTED;
- }
- if (t->flag & T_PROP_PROJECTED) {
- prop_edit_flag |= PROP_EDIT_PROJECTED;
+ /* Save proportional edit settings.
+ * Skip saving proportional edit if it was not actually used. */
+ if (!(t->options & CTX_NO_PET)) {
+ bool use_prop_edit = false;
+ int prop_edit_flag = 0;
+ if (t->flag & T_PROP_EDIT_ALL) {
+ if (t->flag & T_PROP_EDIT) {
+ use_prop_edit = true;
+ }
+ if (t->flag & T_PROP_CONNECTED) {
+ prop_edit_flag |= PROP_EDIT_CONNECTED;
+ }
+ if (t->flag & T_PROP_PROJECTED) {
+ prop_edit_flag |= PROP_EDIT_PROJECTED;
+ }
}
- }
-
- /* If modal, save settings back in scene if not set as operator argument */
- if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
- /* save settings if not set in operator */
- /* skip saving proportional edit if it was not actually used */
- if (!(t->options & CTX_NO_PET)) {
+ /* If modal, save settings back in scene if not set as operator argument */
+ if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
+ /* save settings if not set in operator */
if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) &&
!RNA_property_is_set(op->ptr, prop)) {
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
@@ -1576,6 +1574,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
+ RNA_property_boolean_set(op->ptr, prop, use_prop_edit);
+ RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED);
+ RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED);
+ RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
+ RNA_float_set(op->ptr, "proportional_size", t->prop_size);
+ }
}
/* Save snapping settings. */
@@ -1588,9 +1594,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_select);
eSnapTargetSelect target = t->tsnap.target_select;
- RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) != 0);
- RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) != 0);
- RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) != 0);
+ RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0);
+ RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0);
+ RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0);
RNA_boolean_set(
op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0);
}
@@ -1635,14 +1641,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
- RNA_property_boolean_set(op->ptr, prop, use_prop_edit);
- RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED);
- RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED);
- RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
- RNA_float_set(op->ptr, "proportional_size", t->prop_size);
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
@@ -1723,13 +1721,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
-static void initSnapSpatial(TransInfo *t, float r_snap[2])
+static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision)
{
+ /* Default values. */
+ r_snap[0] = r_snap[1] = 1.0f;
+ r_snap[1] = 0.0f;
+ *r_snap_precision = 0.1f;
+
if (t->spacetype == SPACE_VIEW3D) {
if (t->region->regiondata) {
View3D *v3d = t->area->spacedata.first;
- r_snap[0] = ED_view3d_grid_view_scale(t->scene, v3d, t->region, NULL) * 1.0f;
- r_snap[1] = r_snap[0] * 0.1f;
+ r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale(
+ t->scene, v3d, t->region, NULL);
}
}
else if (t->spacetype == SPACE_IMAGE) {
@@ -1737,33 +1740,22 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
View2D *v2d = &t->region->v2d;
int grid_size = SI_GRID_STEPS_LEN;
float zoom_factor = ED_space_image_zoom_level(v2d, grid_size);
- float grid_steps[SI_GRID_STEPS_LEN];
+ float grid_steps_x[SI_GRID_STEPS_LEN];
float grid_steps_y[SI_GRID_STEPS_LEN];
- ED_space_image_grid_steps(sima, grid_steps, grid_steps_y, grid_size);
+ ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size);
/* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */
- r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps, zoom_factor);
- r_snap[1] = r_snap[0] / 2.0f;
-
- /* TODO: Implement snapping for custom grid sizes with `grid_steps[0] != grid_steps_y[0]`.
- * r_snap_y[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
- * r_snap_y[1] = r_snap_y[0] / 2.0f;
- */
+ r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor);
+ r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
+ *r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_CLIP) {
- r_snap[0] = 0.125f;
- r_snap[1] = 0.0625f;
+ r_snap[0] = r_snap[1] = 0.125f;
+ *r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_NODE) {
r_snap[0] = r_snap[1] = ED_node_grid_size();
}
- else if (t->spacetype == SPACE_GRAPH) {
- r_snap[0] = 1.0;
- r_snap[1] = 0.1f;
- }
- else {
- r_snap[0] = r_snap[1] = 1.0f;
- }
}
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
@@ -1903,7 +1895,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initSnapping(t, op); /* Initialize snapping data AFTER mode flags */
- initSnapSpatial(t, t->snap_spatial);
+ initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision);
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected.
* will be removed (ton) */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 09fc07f57f4..90f2795184b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -19,6 +19,10 @@
#include "transform_data.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* use node center for transform instead of upper-left corner.
* disabled since it makes absolute snapping not work so nicely
*/
@@ -141,6 +145,7 @@ typedef enum {
/** No cursor wrapping on region bounds */
T_NO_CURSOR_WRAP = 1 << 23,
} eTFlag;
+ENUM_OPERATORS(eTFlag, T_NO_CURSOR_WRAP);
#define T_ALL_RESTRICTIONS (T_NO_CONSTRAINT | T_NULL_ONE)
#define T_PROP_EDIT_ALL (T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED)
@@ -550,7 +555,12 @@ typedef struct TransInfo {
/** Snapping Gears. */
float snap[2];
/** Spatial snapping gears(even when rotating, scaling... etc). */
- float snap_spatial[2];
+ float snap_spatial[3];
+ /**
+ * Precision factor that is multiplied to snap_spatial when precision
+ * modifier is enabled for snap to grid or incremental snap.
+ */
+ float snap_spatial_precision;
/** Mouse side of the current frame, 'L', 'R' or 'B' */
char frame_side;
@@ -864,3 +874,7 @@ bool checkUseAxisMatrix(TransInfo *t);
th++, i++)
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index fa56456d8e7..7abf0e5c00c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -404,9 +404,11 @@ static void applyAxisConstraintVec(const TransInfo *t,
}
}
+ /* Fallback for when axes are aligned. */
+ mul_m3_v3(t->con.pmtx, out);
+
if (is_snap_to_point) {
- /* With snap points, a projection is alright, no adjustments needed. */
- mul_m3_v3(t->con.pmtx, out);
+ /* Pass. With snap points, a projection is alright, no adjustments needed. */
}
else {
const int dims = getConstraintSpaceDimension(t);
@@ -422,14 +424,9 @@ static void applyAxisConstraintVec(const TransInfo *t,
/* Disabled, as it has not proven to be really useful. (See T82386). */
// constraint_snap_plane_to_face(t, plane, out);
}
- else {
+ else if (!isPlaneProjectionViewAligned(t, plane)) {
/* View alignment correction. */
- if (!isPlaneProjectionViewAligned(t, plane)) {
- planeProjection(t, plane, in, out);
- }
- else {
- mul_m3_v3(t->con.pmtx, out);
- }
+ planeProjection(t, plane, in, out);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index f32bff6dcff..4798d666d70 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -10,6 +10,10 @@
#include "RE_engine.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMEditMesh;
struct BMesh;
struct BezTriple;
@@ -222,8 +226,6 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3],
struct TransData *r_td);
void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data);
-void special_aftertrans_update__mesh(bContext *C, TransInfo *t);
-
/* transform_convert_mesh_edge.c */
extern TransConvertTypeInfo TransConvertType_MeshEdge;
@@ -244,7 +246,7 @@ extern TransConvertTypeInfo TransConvertType_MeshVertCData;
extern TransConvertTypeInfo TransConvertType_NLA;
-/* transform_convert_node.c */
+/* transform_convert_node.cc */
extern TransConvertTypeInfo TransConvertType_Node;
@@ -279,3 +281,7 @@ extern TransConvertTypeInfo TransConvertType_SequencerImage;
/* transform_convert_tracking.c */
extern TransConvertTypeInfo TransConvertType_Tracking;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index af7982f862a..7e237c9eb32 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -2068,7 +2068,7 @@ static void recalcData_mesh(TransInfo *t)
/** \name Special After Transform Mesh
* \{ */
-void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
+static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
const bool is_canceling = (t->state == TRANS_CANCEL);
const bool use_automerge = !is_canceling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 7f26029850b..0ce4c592f53 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -125,5 +125,5 @@ TransConvertTypeInfo TransConvertType_MeshEdge = {
/* flags */ T_EDIT,
/* createTransData */ createTransEdge,
/* recalcData */ recalcData_mesh_edge,
- /* special_aftertrans_update */ special_aftertrans_update__mesh,
+ /* special_aftertrans_update */ NULL,
};
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index cfa933d1600..af5a51cbff6 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -56,6 +56,29 @@ typedef struct TransDataNla {
} TransDataNla;
/* -------------------------------------------------------------------- */
+/** \name Transform application to NLA strips
+ * \{ */
+
+/**
+ * \brief Applies a translation to the given NlaStrip.
+ * \param strip_rna_ptr The RNA pointer of the NLA strip to modify.
+ * \param transdata The transformation info structure.
+ */
+static void applyTransformNLA_translation(PointerRNA *strip_rna_ptr, const TransDataNla *transdata)
+{
+ /* NOTE: we write these twice to avoid truncation errors which can arise when
+ * moving the strips a large distance using numeric input T33852.
+ */
+ RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]);
+ RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]);
+
+ RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]);
+ RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name NLA Transform Creation
* \{ */
@@ -329,15 +352,8 @@ static void recalcData_nla(TransInfo *t)
*
* this is done as a iterative procedure (done 5 times max for now)
*/
- NlaStrip *prev = strip->prev;
- while (prev != NULL && (prev->type & NLASTRIP_TYPE_TRANSITION)) {
- prev = prev->prev;
- }
-
- NlaStrip *next = strip->next;
- while (next != NULL && (next->type & NLASTRIP_TYPE_TRANSITION)) {
- next = next->next;
- }
+ NlaStrip *prev = BKE_nlastrip_prev_in_track(strip, true);
+ NlaStrip *next = BKE_nlastrip_next_in_track(strip, true);
for (short iter = 0; iter < 5; iter++) {
const bool pExceeded = (prev != NULL) && (tdn->h1[0] < prev->end);
@@ -380,17 +396,10 @@ static void recalcData_nla(TransInfo *t)
/* Use RNA to write the values to ensure that constraints on these are obeyed
* (e.g. for transition strips, the values are taken from the neighbors)
- *
- * NOTE: we write these twice to avoid truncation errors which can arise when
- * moving the strips a large distance using numeric input T33852.
*/
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
-
- RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
- RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
+ applyTransformNLA_translation(&strip_ptr, tdn);
/* flush transforms to child strips (since this should be a meta) */
BKE_nlameta_flush_transforms(strip);
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.cc
index ed19789fdd8..6ab0e1fe701 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.cc
@@ -96,13 +96,13 @@ static bool is_node_parent_select(bNode *node)
return false;
}
-static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
+static void createTransNodeData(bContext * /*C*/, TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
- SpaceNode *snode = t->area->spacedata.first;
+ SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
/* Custom data to enable edge panning during the node transform */
- struct TransCustomDataNode *customdata = MEM_callocN(sizeof(*customdata), __func__);
+ TransCustomDataNode *customdata = MEM_cnew<TransCustomDataNode>(__func__);
UI_view2d_edge_pan_init(t->context,
&customdata->edgepan_data,
NODE_EDGE_PAN_INSIDE_PAD,
@@ -125,7 +125,7 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
}
/* Nodes don't support PET and probably never will. */
- t->flag &= ~T_PROP_EDIT_ALL;
+ t->flag = t->flag & ~T_PROP_EDIT_ALL;
/* set transform flags on nodes */
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
@@ -142,9 +142,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
return;
}
- TransData *td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
- TransData2D *td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransNode TransData2D");
+ TransData *td = tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__);
+ TransData2D *td2d = tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if (node->flag & NODE_TRANSFORM) {
@@ -156,14 +155,59 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Node Transform Creation
+/** \name Flush Transform Nodes
* \{ */
+static void node_snap_grid_apply(TransInfo *t)
+{
+ int i;
+
+ if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
+ return;
+ }
+
+ float grid_size[2];
+ copy_v2_v2(grid_size, t->snap_spatial);
+ if (t->modifiers & MOD_PRECISION) {
+ mul_v2_fl(grid_size, t->snap_spatial_precision);
+ }
+
+ /* Early exit on unusable grid size. */
+ if (is_zero_v2(grid_size)) {
+ return;
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td;
+
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ float iloc[2], loc[2], tvec[2];
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
+ continue;
+ }
+
+ copy_v2_v2(iloc, td->loc);
+
+ loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0];
+ loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1];
+
+ sub_v2_v2v2(tvec, loc, iloc);
+ add_v2_v2(td->loc, tvec);
+ }
+ }
+}
+
static void flushTransNodes(TransInfo *t)
{
+ using namespace blender::ed;
const float dpi_fac = UI_DPI_FAC;
+ SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
- struct TransCustomDataNode *customdata = (struct TransCustomDataNode *)t->custom.type.data;
+ TransCustomDataNode *customdata = (TransCustomDataNode *)t->custom.type.data;
if (t->options & CTX_VIEW2D_EDGE_PAN) {
if (t->state == TRANS_CANCEL) {
@@ -190,13 +234,13 @@ static void flushTransNodes(TransInfo *t)
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- applyGridAbsolute(t);
+ node_snap_grid_apply(t);
/* flush to 2d vector from internally used 3d vector */
for (int i = 0; i < tc->data_len; i++) {
TransData *td = &tc->data[i];
TransData2D *td2d = &tc->data_2d[i];
- bNode *node = td->extra;
+ bNode *node = static_cast<bNode *>(td->extra);
float loc[2];
add_v2_v2v2(loc, td2d->loc, offset);
@@ -221,7 +265,7 @@ static void flushTransNodes(TransInfo *t)
/* handle intersection with noodles */
if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->area, 1);
+ space_node::node_insert_on_link_flags_set(*snode, *t->region);
}
}
}
@@ -234,13 +278,15 @@ static void flushTransNodes(TransInfo *t)
static void special_aftertrans_update__node(bContext *C, TransInfo *t)
{
- struct Main *bmain = CTX_data_main(C);
+ using namespace blender::ed;
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
+ bNodeTree *ntree = snode->edittree;
+
const bool canceled = (t->state == TRANS_CANCEL);
- SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
if (canceled && t->remove_on_cancel) {
/* remove selected nodes on cancel */
- bNodeTree *ntree = snode->edittree;
if (ntree) {
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_SELECT) {
@@ -253,11 +299,10 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
if (!canceled) {
ED_node_post_apply_transform(C, snode->edittree);
- ED_node_link_insert(bmain, t->area);
+ space_node::node_insert_on_link_flags(*bmain, *snode);
}
- /* clear link line */
- ED_node_link_intersect_test(t->area, 0);
+ space_node::node_insert_on_link_flags_clear(*ntree);
}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index f7f9e14b8ac..0b87b45679a 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_string.h"
#include "BKE_context.h"
@@ -62,7 +63,14 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
if (td->val) {
- *td->val = td->ival * ratio;
+ if (td->ival == 0.0f && ratio > 1.0f) {
+ /* Allow Shrink/Fatten for zero radius. */
+ *td->val = (ratio - 1.0f) * uint_as_float(POINTER_AS_UINT(t->custom.mode.data));
+ }
+ else {
+ *td->val = td->ival * ratio;
+ }
+
/* apply PET */
*td->val = interpf(*td->val, td->ival, td->factor);
CLAMP_MIN(*td->val, 0.0f);
@@ -92,6 +100,18 @@ void initCurveShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_CONSTRAINT;
+
+ float scale_factor = 0.0f;
+ if (((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW) &&
+ (t->data_len_all == 1)) ||
+ (t->data_len_all == 3 && TRANS_DATA_CONTAINER_FIRST_OK(t)->data[0].val == NULL)) {
+ /* For cases where only one point on the curve is being transformed and the radius of that
+ * point is zero, use the factor to multiply the offset of the ratio and allow scaling.
+ * Note that for bezier curves, 3 TransData equals 1 point in most cases. */
+ RegionView3D *rv3d = t->region->regiondata;
+ scale_factor = rv3d->pixsize * t->mouse.factor * t->zfac;
+ }
+ t->custom.mode.data = POINTER_FROM_UINT(float_as_uint(scale_factor));
}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 8f6ec7bd98f..59d34c3918b 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -170,7 +170,7 @@ static void transdata_elem_translate_fn(void *__restrict iter_data_v,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Transform (Translation)
+/** \name Transform (Translation) Header
* \{ */
static void translate_dist_to_str(char *r_str,
@@ -341,6 +341,96 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (Translation) Snapping
+ * \{ */
+
+static void translate_snap_target_grid_ensure(TransInfo *t)
+{
+ /* Only need to calculate once. */
+ if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
+ if (t->data_type == &TransConvertType_Cursor3D) {
+ /* Use a fallback when transforming the cursor.
+ * In this case the center is _not_ derived from the cursor which is being transformed. */
+ copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
+ }
+ else if (t->around == V3D_AROUND_CURSOR) {
+ /* Use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ tranform_snap_target_median_calc(t, t->tsnap.snapTargetGrid);
+ }
+ else {
+ copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
+ }
+ t->tsnap.status |= TARGET_GRID_INIT;
+ }
+}
+
+static void translate_snap_grid_apply(TransInfo *t,
+ const int max_index,
+ const float grid_dist[3],
+ const float loc[3],
+ float r_out[3])
+{
+ BLI_assert(max_index <= 2);
+ translate_snap_target_grid_ensure(t);
+ const float *center_global = t->tsnap.snapTargetGrid;
+ const float *asp = t->aspect;
+
+ float in[3];
+ if (t->con.mode & CON_APPLY) {
+ BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
+ t->con.applyVec(t, NULL, NULL, loc, in);
+ }
+ else {
+ copy_v3_v3(in, loc);
+ }
+
+ for (int i = 0; i <= max_index; i++) {
+ const float iter_fac = grid_dist[i] * asp[i];
+ r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
+ }
+}
+
+static bool translate_snap_grid(TransInfo *t, float *val)
+{
+ if (!activeSnap(t)) {
+ return false;
+ }
+
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) {
+ /* Don't do grid snapping if there is a valid snap point. */
+ return false;
+ }
+
+ /* Don't do grid snapping if not in 3D viewport or UV editor */
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
+ return false;
+ }
+
+ if (t->mode != TFM_TRANSLATION) {
+ return false;
+ }
+
+ float grid_dist[3];
+ copy_v3_v3(grid_dist, t->snap_spatial);
+ if (t->modifiers & MOD_PRECISION) {
+ mul_v3_fl(grid_dist, t->snap_spatial_precision);
+ }
+
+ /* Early bailing out if no need to snap */
+ if (is_zero_v3(grid_dist)) {
+ return false;
+ }
+
+ translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val);
+ t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
+ return true;
+}
+
static void ApplySnapTranslation(TransInfo *t, float vec[3])
{
float point[3];
@@ -372,6 +462,12 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (Translation)
+ * \{ */
+
static void applyTranslationValue(TransInfo *t, const float vec[3])
{
struct TranslateCustomData *custom_data = t->custom.mode.data;
@@ -514,7 +610,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
applySnappingAsGroup(t, global_dir);
- transform_snap_grid(t, global_dir);
+ translate_snap_grid(t, global_dir);
if (t->con.mode & CON_APPLY) {
float in[3];
@@ -590,7 +686,8 @@ void initTranslation(TransInfo *t)
t->num.flag = 0;
t->num.idx_max = t->idx_max;
- copy_v2_v2(t->snap, t->snap_spatial);
+ t->snap[0] = t->snap_spatial[0];
+ t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision;
copy_v3_fl(t->num.val_inc, t->snap[0]);
t->num.unit_sys = t->scene->unit.system;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index dbda9a26bbf..82791b2a9f5 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -523,9 +523,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static bool transform_poll_property(const bContext *UNUSED(C),
- wmOperator *op,
- const PropertyRNA *prop)
+static bool transform_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
@@ -559,12 +557,21 @@ static bool transform_poll_property(const bContext *UNUSED(C),
}
/* Proportional Editing. */
- {
+ if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_NLA) {
+ /* Hide properties that are not supported in some spaces. */
+ return false;
+ }
+
PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "use_proportional_edit");
- if (prop_pet && (prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) {
- if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) {
- return false;
- }
+ if ((prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) {
+ /* If "use_proportional_edit" is false, hide:
+ * - "proportional_edit_falloff",
+ * - "proportional_size",
+ * - "use_proportional_connected",
+ * - "use_proportional_projected". */
+ return false;
}
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 3f9cca55138..672d947936d 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -511,56 +511,6 @@ void applySnappingIndividual(TransInfo *t)
}
}
-void applyGridAbsolute(TransInfo *t)
-{
- int i;
-
- if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
- return;
- }
-
- float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[1] : t->snap_spatial[0];
-
- /* early exit on unusable grid size */
- if (grid_size == 0.0f) {
- return;
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td;
-
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- float iloc[3], loc[3], tvec[3];
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
- continue;
- }
-
- copy_v3_v3(iloc, td->loc);
- if (tc->use_local_mat) {
- mul_m4_v3(tc->mat, iloc);
- }
- else if (t->options & CTX_OBJECT) {
- BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
-
- mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
- loc[0] = roundf(loc[0]);
- loc[1] = roundf(loc[1]);
- loc[2] = roundf(loc[2]);
- mul_v3_fl(loc, grid_size);
-
- sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
- }
- }
-}
-
void applySnappingAsGroup(TransInfo *t, float *vec)
{
if (!activeSnap_SnappingAsGroup(t)) {
@@ -1187,7 +1137,7 @@ static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec))
/** \name Target
* \{ */
-static void snap_target_median_impl(TransInfo *t, float r_median[3])
+void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3])
{
int i_accum = 0;
@@ -1223,28 +1173,6 @@ static void snap_target_median_impl(TransInfo *t, float r_median[3])
// TargetSnapOffset(t, NULL);
}
-static void snap_target_grid_ensure(TransInfo *t)
-{
- /* Only need to calculate once. */
- if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
- if (t->data_type == &TransConvertType_Cursor3D) {
- /* Use a fallback when transforming the cursor.
- * In this case the center is _not_ derived from the cursor which is being transformed. */
- copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
- }
- else if (t->around == V3D_AROUND_CURSOR) {
- /* Use a fallback for cursor selection,
- * this isn't useful as a global center for absolute grid snapping
- * since its not based on the position of the selection. */
- snap_target_median_impl(t, t->tsnap.snapTargetGrid);
- }
- else {
- copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
- }
- t->tsnap.status |= TARGET_GRID_INIT;
- }
-}
-
static void TargetSnapOffset(TransInfo *t, TransData *td)
{
if (t->spacetype == SPACE_NODE && td != NULL) {
@@ -1316,7 +1244,7 @@ static void TargetSnapMedian(TransInfo *t)
{
/* Only need to calculate once. */
if ((t->tsnap.status & TARGET_INIT) == 0) {
- snap_target_median_impl(t, t->tsnap.snapTarget);
+ tranform_snap_target_median_calc(t, t->tsnap.snapTarget);
t->tsnap.status |= TARGET_INIT;
}
}
@@ -1654,61 +1582,6 @@ bool snapNodesTransform(
/** \name snap Grid
* \{ */
-static void snap_grid_apply(
- TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
-{
- BLI_assert(max_index <= 2);
- snap_target_grid_ensure(t);
- const float *center_global = t->tsnap.snapTargetGrid;
- const float *asp = t->aspect;
-
- float in[3];
- if (t->con.mode & CON_APPLY) {
- BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
- t->con.applyVec(t, NULL, NULL, loc, in);
- }
- else {
- copy_v3_v3(in, loc);
- }
-
- for (int i = 0; i <= max_index; i++) {
- const float iter_fac = grid_dist * asp[i];
- r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
- }
-}
-
-bool transform_snap_grid(TransInfo *t, float *val)
-{
- if (!activeSnap(t)) {
- return false;
- }
-
- if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) {
- /* Don't do grid snapping if there is a valid snap point. */
- return false;
- }
-
- /* Don't do grid snapping if not in 3D viewport or UV editor */
- if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
- return false;
- }
-
- if (t->mode != TFM_TRANSLATION) {
- return false;
- }
-
- float grid_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
-
- /* Early bailing out if no need to snap */
- if (grid_dist == 0.0f) {
- return false;
- }
-
- snap_grid_apply(t, t->idx_max, grid_dist, val, val);
- t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
- return true;
-}
-
static void snap_increment_apply_ex(const TransInfo *UNUSED(t),
const int max_index,
const float increment_val,
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index 3672e76c778..16d9062e978 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -11,6 +11,10 @@
/* For enum. */
#include "DNA_space_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
bool use_peel_object,
@@ -34,10 +38,10 @@ bool snapNodesTransform(struct TransInfo *t,
bool transformModeUseSnap(const TransInfo *t);
+void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
float transform_snap_increment_get(const TransInfo *t);
-bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
bool activeSnap_SnappingIndividual(const TransInfo *t);
@@ -48,7 +52,6 @@ bool validSnap(const TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
void freeSnapping(struct TransInfo *t);
void applySnappingIndividual(TransInfo *t);
-void applyGridAbsolute(TransInfo *t);
void applySnappingAsGroup(TransInfo *t, float *vec);
void resetSnapping(TransInfo *t);
eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event);
@@ -92,3 +95,7 @@ void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
eAnimEdit_AutoSnap autosnap,
float *r_val_final);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 90a13722b63..7971e1ca9af 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -105,7 +105,7 @@ struct SnapData_EditMesh {
/* Looptris. */
BVHTreeFromEditMesh treedata_editmesh;
- struct Mesh_Runtime *mesh_runtime;
+ blender::bke::MeshRuntime *mesh_runtime;
float min[3], max[3];
void clear()
@@ -189,14 +189,14 @@ static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type,
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
- if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_final;
use_hide = true;
}
else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
- if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return nullptr;
}
me_eval = editmesh_eval_cage;
@@ -253,21 +253,21 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
sod = sod_p->get();
bool is_dirty = false;
if (sod->treedata_mesh.tree && sod->treedata_mesh.cached &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->treedata_mesh.tree)) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
- !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) {
+ !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the Mesh and may have been freed since we last used. */
is_dirty = true;
}
- else if (sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) {
+ else if (sod->treedata_mesh.looptri != me_eval->looptris().data()) {
is_dirty = true;
}
else if (sod->treedata_mesh.vert != verts.data()) {
@@ -330,19 +330,19 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
/* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due
* to changes in the `edit_mesh`. */
-static Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
+static blender::bke::MeshRuntime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
if (editmesh_eval_final) {
- return &editmesh_eval_final->runtime;
+ return editmesh_eval_final->runtime;
}
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
if (editmesh_eval_cage) {
- return &editmesh_eval_cage->runtime;
+ return editmesh_eval_cage->runtime;
}
- return &((Mesh *)ob_eval->data)->runtime;
+ return ((Mesh *)ob_eval->data)->runtime;
}
static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
@@ -457,7 +457,7 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon
4,
BVHTREE_FROM_EM_LOOPTRI,
&sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ &sod->mesh_runtime->eval_mutex);
}
}
if (treedata == nullptr || treedata->tree == nullptr) {
@@ -2923,7 +2923,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
2,
BVHTREE_FROM_EM_VERTS,
&sod->mesh_runtime->bvh_cache,
- (ThreadMutex *)sod->mesh_runtime->eval_mutex);
+ &sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
sod->cached[0] = treedata.cached;
@@ -2955,7 +2955,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
2,
BVHTREE_FROM_EM_EDGES,
&sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ &sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
sod->cached[1] = treedata.cached;
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 12e77c6ef00..92d65688bf1 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -374,7 +374,7 @@ void unpack_menu(bContext *C,
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
- BLI_path_join(local_name, sizeof(local_name), "//", folder, fi, NULL);
+ BLI_path_join(local_name, sizeof(local_name), "//", folder, fi);
if (!STREQ(abs_name, local_name)) {
switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc
index 5c03367cba8..4da1559b726 100644
--- a/source/blender/editors/util/ed_viewer_path.cc
+++ b/source/blender/editors/util/ed_viewer_path.cc
@@ -249,6 +249,9 @@ bool is_active_geometry_nodes_viewer(const bContext &C,
if (md->type != eModifierType_Nodes) {
return false;
}
+ if ((md->mode & eModifierMode_Realtime) == 0) {
+ return false;
+ }
modifier = reinterpret_cast<const NodesModifierData *>(md);
break;
}
diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc
index 2648ec5e2f6..92745667505 100644
--- a/source/blender/editors/uvedit/uvedit_islands.cc
+++ b/source/blender/editors/uvedit/uvedit_islands.cc
@@ -403,6 +403,219 @@ int bm_mesh_calc_uv_islands(const Scene *scene,
/** \} */
+static float pack_islands_scale_margin(const blender::Vector<FaceIsland *> &island_vector,
+ BoxPack *box_array,
+ const float scale,
+ const float margin)
+{
+ for (const int index : island_vector.index_range()) {
+ FaceIsland *island = island_vector[index];
+ BoxPack *box = &box_array[index];
+ box->index = index;
+ box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin;
+ box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin;
+ }
+ float max_u, max_v;
+ BLI_box_pack_2d(box_array, island_vector.size(), &max_u, &max_v);
+ return max_ff(max_u, max_v);
+}
+
+static float pack_islands_margin_fraction(const blender::Vector<FaceIsland *> &island_vector,
+ BoxPack *box_array,
+ const float margin_fraction)
+{
+ /*
+ * Root finding using a combined search / modified-secant method.
+ * First, use a robust search procedure to bracket the root within a factor of 10.
+ * Then, use a modified-secant method to converge.
+ *
+ * This is a specialized solver using domain knowledge to accelerate convergence.
+ */
+
+ float scale_low = 0.0f;
+ float value_low = 0.0f;
+ float scale_high = 0.0f;
+ float value_high = 0.0f;
+ float scale_last = 0.0f;
+
+ /* Scaling smaller than `min_scale_roundoff` is unlikely to fit and
+ * will destroy information in existing UVs. */
+ float min_scale_roundoff = 1e-5f;
+
+ /* Certain inputs might have poor convergence properties.
+ * Use `max_iteration` to prevent an infinite loop. */
+ int max_iteration = 25;
+ for (int iteration = 0; iteration < max_iteration; iteration++) {
+ float scale = 1.0f;
+
+ if (iteration == 0) {
+ BLI_assert(iteration == 0);
+ BLI_assert(scale == 1.0f);
+ BLI_assert(scale_low == 0.0f);
+ BLI_assert(scale_high == 0.0f);
+ }
+ else if (scale_low == 0.0f) {
+ BLI_assert(scale_high > 0.0f);
+ /* Search mode, shrink layout until we can find a scale that fits. */
+ scale = scale_high * 0.1f;
+ }
+ else if (scale_high == 0.0f) {
+ BLI_assert(scale_low > 0.0f);
+ /* Search mode, grow layout until we can find a scale that doesn't fit. */
+ scale = scale_low * 10.0f;
+ }
+ else {
+ /* Bracket mode, use modified secant method to find root. */
+ BLI_assert(scale_low > 0.0f);
+ BLI_assert(scale_high > 0.0f);
+ BLI_assert(value_low <= 0.0f);
+ BLI_assert(value_high >= 0.0f);
+ if (scale_high < scale_low * 1.0001f) {
+ /* Convergence. */
+ break;
+ }
+
+ /* Secant method for area. */
+ scale = (sqrtf(scale_low) * value_high - sqrtf(scale_high) * value_low) /
+ (value_high - value_low);
+ scale = scale * scale;
+
+ if (iteration & 1) {
+ /* Modified binary-search to improve robustness. */
+ scale = sqrtf(scale * sqrtf(scale_low * scale_high));
+ }
+ }
+
+ scale = max_ff(scale, min_scale_roundoff);
+
+ /* Evaluate our `f`. */
+ scale_last = scale;
+ float max_uv = pack_islands_scale_margin(
+ island_vector, box_array, scale_last, margin_fraction);
+ float value = sqrtf(max_uv) - 1.0f;
+
+ if (value <= 0.0f) {
+ scale_low = scale;
+ value_low = value;
+ }
+ else {
+ scale_high = scale;
+ value_high = value;
+ if (scale == min_scale_roundoff) {
+ /* Unable to pack without damaging UVs. */
+ scale_low = scale;
+ break;
+ }
+ }
+ }
+
+ const bool flush = true;
+ if (flush) {
+ /* Write back best pack as a side-effect. First get best pack. */
+ if (scale_last != scale_low) {
+ scale_last = scale_low;
+ float max_uv = pack_islands_scale_margin(
+ island_vector, box_array, scale_last, margin_fraction);
+ UNUSED_VARS(max_uv);
+ /* TODO (?): `if (max_uv < 1.0f) { scale_last /= max_uv; }` */
+ }
+
+ /* Then expand FaceIslands by the correct amount. */
+ for (const int index : island_vector.index_range()) {
+ BoxPack *box = &box_array[index];
+ box->x /= scale_last;
+ box->y /= scale_last;
+ FaceIsland *island = island_vector[index];
+ BLI_rctf_pad(
+ &island->bounds_rect, margin_fraction / scale_last, margin_fraction / scale_last);
+ }
+ }
+ return scale_last;
+}
+
+static float calc_margin_from_aabb_length_sum(const blender::Vector<FaceIsland *> &island_vector,
+ const struct UVPackIsland_Params &params)
+{
+ /* Logic matches behavior from #GEO_uv_parametrizer_pack.
+ * Attempt to give predictable results
+ * not dependent on current UV scale by using
+ * `aabb_length_sum` (was "`area`") to multiply
+ * the margin by the length (was "area").
+ */
+ double aabb_length_sum = 0.0f;
+ for (FaceIsland *island : island_vector) {
+ float w = BLI_rctf_size_x(&island->bounds_rect);
+ float h = BLI_rctf_size_y(&island->bounds_rect);
+ aabb_length_sum += sqrtf(w * h);
+ }
+ return params.margin * aabb_length_sum * 0.1f;
+}
+
+static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_vector,
+ const struct UVPackIsland_Params &params,
+ float r_scale[2])
+{
+ BoxPack *box_array = static_cast<BoxPack *>(
+ MEM_mallocN(sizeof(*box_array) * island_vector.size(), __func__));
+
+ if (params.margin == 0.0f) {
+ /* Special case for zero margin. Margin_method is ignored as all formulas give same result. */
+ const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, 0.0f);
+ r_scale[0] = 1.0f / max_uv;
+ r_scale[1] = r_scale[0];
+ return box_array;
+ }
+
+ if (params.margin_method == ED_UVPACK_MARGIN_FRACTION) {
+ /* Uses a line search on scale. ~10x slower than other method. */
+ const float scale = pack_islands_margin_fraction(island_vector, box_array, params.margin);
+ r_scale[0] = scale;
+ r_scale[1] = scale;
+ /* pack_islands_margin_fraction will pad FaceIslands, return early. */
+ return box_array;
+ }
+
+ float margin = params.margin;
+ switch (params.margin_method) {
+ case ED_UVPACK_MARGIN_ADD: /* Default for Blender 2.8 and earlier. */
+ break; /* Nothing to do. */
+ case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
+ margin = calc_margin_from_aabb_length_sum(island_vector, params);
+ break;
+ case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
+ BLI_assert_unreachable(); /* Handled above. */
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+
+ const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, margin);
+ r_scale[0] = 1.0f / max_uv;
+ r_scale[1] = r_scale[0];
+
+ for (int index = 0; index < island_vector.size(); index++) {
+ FaceIsland *island = island_vector[index];
+ BLI_rctf_pad(&island->bounds_rect, margin, margin);
+ }
+ return box_array;
+}
+
+static bool island_has_pins(FaceIsland *island)
+{
+ BMLoop *l;
+ BMIter iter;
+ const int cd_loop_uv_offset = island->cd_loop_uv_offset;
+ for (int i = 0; i < island->faces_len; i++) {
+ BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset));
+ if (luv->flag & MLOOPUV_PINNED) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public UV Island Packing
*
@@ -412,6 +625,7 @@ int bm_mesh_calc_uv_islands(const Scene *scene,
void ED_uvedit_pack_islands_multi(const Scene *scene,
Object **objects,
const uint objects_len,
+ BMesh **bmesh_override,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params)
{
@@ -419,9 +633,17 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BMesh *bm = nullptr;
+ if (bmesh_override) {
+ /* Note: obedit is still required for aspect ratio and ID_RECALC_GEOMETRY. */
+ bm = bmesh_override[ob_index];
+ }
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bm = em->bm;
+ }
+ BLI_assert(bm);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
@@ -437,7 +659,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
ListBase island_list = {nullptr};
bm_mesh_calc_uv_islands(scene,
- em->bm,
+ bm,
&island_list,
params->only_selected_faces,
params->only_selected_uvs,
@@ -445,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
aspect_y,
cd_loop_uv_offset);
- int index;
- LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
+ /* Remove from linked list and append to blender::Vector. */
+ LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) {
+ BLI_remlink(&island_list, island);
+ if (params->ignore_pinned && island_has_pins(island)) {
+ MEM_freeN(island->faces);
+ MEM_freeN(island);
+ continue;
+ }
island_vector.append(island);
}
}
@@ -455,19 +683,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
return;
}
- float margin = scene->toolsettings->uvcalc_margin;
- double area = 0.0f;
-
- BoxPack *boxarray = static_cast<BoxPack *>(
- MEM_mallocN(sizeof(*boxarray) * island_vector.size(), __func__));
-
/* Coordinates of bounding box containing all selected UVs. */
float selection_min_co[2], selection_max_co[2];
INIT_MINMAX2(selection_min_co, selection_max_co);
for (int index = 0; index < island_vector.size(); index++) {
FaceIsland *island = island_vector[index];
-
/* Skip calculation if using specified UDIM option. */
if (udim_params && (udim_params->use_target_udim == false)) {
float bounds_min[2], bounds_max[2];
@@ -489,17 +710,6 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
bm_face_array_calc_bounds(
island->faces, island->faces_len, island->cd_loop_uv_offset, &island->bounds_rect);
-
- BoxPack *box = &boxarray[index];
- box->index = index;
- box->x = 0.0f;
- box->y = 0.0f;
- box->w = BLI_rctf_size_x(&island->bounds_rect);
- box->h = BLI_rctf_size_y(&island->bounds_rect);
-
- if (margin > 0.0f) {
- area += double(sqrtf(box->w * box->h));
- }
}
/* Center of bounding box containing all selected UVs. */
@@ -509,28 +719,8 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
}
- if (margin > 0.0f) {
- /* Logic matches behavior from #GEO_uv_parametrizer_pack,
- * use area so multiply the margin by the area to give
- * predictable results not dependent on UV scale. */
- margin = (margin * float(area)) * 0.1f;
- for (int i = 0; i < island_vector.size(); i++) {
- FaceIsland *island = island_vector[i];
- BoxPack *box = &boxarray[i];
-
- BLI_rctf_pad(&island->bounds_rect, margin, margin);
- box->w = BLI_rctf_size_x(&island->bounds_rect);
- box->h = BLI_rctf_size_y(&island->bounds_rect);
- }
- }
-
- float boxarray_size[2];
- BLI_box_pack_2d(boxarray, island_vector.size(), &boxarray_size[0], &boxarray_size[1]);
-
- /* Don't change the aspect when scaling. */
- boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
-
- const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]};
+ float scale[2] = {1.0f, 1.0f};
+ BoxPack *box_array = pack_islands_params(island_vector, *params, scale);
/* Tile offset. */
float base_offset[2] = {0.0f, 0.0f};
@@ -580,14 +770,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
}
for (int i = 0; i < island_vector.size(); i++) {
- FaceIsland *island = island_vector[boxarray[i].index];
+ FaceIsland *island = island_vector[box_array[i].index];
const float pivot[2] = {
island->bounds_rect.xmin,
island->bounds_rect.ymin,
};
const float offset[2] = {
- ((boxarray[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
- ((boxarray[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
+ ((box_array[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
+ ((box_array[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
};
for (int j = 0; j < island->faces_len; j++) {
BMFace *efa = island->faces[j];
@@ -607,7 +797,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
MEM_freeN(island);
}
- MEM_freeN(boxarray);
+ MEM_freeN(box_array);
}
/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 5e2d9097abd..b65f4889347 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -37,6 +37,7 @@
#include "BKE_node.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -113,7 +114,8 @@ bool ED_object_get_active_image(Object *ob,
bNode **r_node,
bNodeTree **r_ntree)
{
- Material *ma = BKE_object_material_get(ob, mat_nr);
+ Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) :
+ BKE_object_material_get(ob, mat_nr);
bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 661a2a1b05b..ecaba3234a7 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1050,50 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/** \name Pack UV Islands Operator
* \{ */
-static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
-{
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .only_selected_faces = false,
- .only_selected_uvs = true,
- .fill_holes = false,
- .correct_aspect = false,
- };
-
- bool rotate = true;
- bool ignore_pinned = false;
-
- ParamHandle *handle = construct_param_handle(scene, ob, bm, &options, NULL);
- GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- GEO_uv_parametrizer_flush(handle);
- GEO_uv_parametrizer_delete(handle);
-}
-
-/**
- * \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637).
- * Use #ED_uvedit_pack_islands_multi for a more general solution.
- *
- * TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi.
- */
-static void uvedit_pack_islands_multi(const Scene *scene,
- Object **objects,
- const uint objects_len,
- const UnwrapOptions *options,
- bool rotate,
- bool ignore_pinned)
-{
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
- GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- GEO_uv_parametrizer_flush(handle);
- GEO_uv_parametrizer_delete(handle);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
- }
-}
-
/* Packing targets. */
enum {
PACK_UDIM_SRC_CLOSEST = 0,
@@ -1125,7 +1081,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
}
/* RNA props */
- const bool rotate = RNA_boolean_get(op->ptr, "rotate");
const int udim_source = RNA_enum_get(op->ptr, "udim_source");
if (RNA_struct_property_is_set(op->ptr, "margin")) {
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
@@ -1139,21 +1094,42 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
sima, use_active, &udim_params);
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = RNA_boolean_get(op->ptr, "rotate"),
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = false,
+ .margin_method = RNA_enum_get(op->ptr, "margin_method"),
+ .margin = RNA_float_get(op->ptr, "margin"),
+ };
ED_uvedit_pack_islands_multi(scene,
objects,
objects_len,
+ NULL,
use_udim_params ? &udim_params : NULL,
- &(struct UVPackIsland_Params){
- .rotate = rotate,
- .only_selected_uvs = true,
- .only_selected_faces = true,
- .correct_aspect = true,
- });
+ &pack_island_params);
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
+const EnumPropertyItem pack_margin_method[] = {
+ {ED_UVPACK_MARGIN_SCALED,
+ "SCALED",
+ 0,
+ "Scaled",
+ "Use scale of existing UVs to multiply margin"},
+ {ED_UVPACK_MARGIN_ADD, "ADD", 0, "Add", "Just add the margin, ignoring any UV scale"},
+ {ED_UVPACK_MARGIN_FRACTION,
+ "FRACTION",
+ 0,
+ "Fraction",
+ "Specify a precise fraction of final UV output"},
+ {0, NULL, 0, NULL, NULL},
+};
+
void UV_OT_pack_islands(wmOperatorType *ot)
{
static const EnumPropertyItem pack_target[] = {
@@ -1180,6 +1156,8 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", "");
RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
@@ -1892,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
-
- bool rotate = true;
- bool ignore_pinned = true;
-
uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = true,
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = true,
+ .margin_method = ED_UVPACK_MARGIN_SCALED,
+ .margin = scene->toolsettings->uvcalc_margin,
+ };
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params);
}
}
@@ -1929,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
- bool rotate = true;
- bool ignore_pinned = true;
if (CTX_wm_space_image(C)) {
/* Inside the UV Editor, only unwrap selected UVs. */
options.only_selected_uvs = true;
@@ -2035,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.count_failed = 0,
};
uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+
+ const struct UVPackIsland_Params pack_island_params = {
+ .rotate = true,
+ .only_selected_uvs = options.only_selected_uvs,
+ .only_selected_faces = options.only_selected_faces,
+ .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
+ .correct_aspect = options.correct_aspect,
+ .ignore_pinned = true,
+ .margin_method = RNA_enum_get(op->ptr, "margin_method"),
+ .margin = RNA_float_get(op->ptr, "margin"),
+ };
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params);
MEM_freeN(objects);
@@ -2098,6 +2092,8 @@ void UV_OT_unwrap(wmOperatorType *ot)
0,
"Use Subdivision Surface",
"Map UVs taking vertex position after Subdivision Surface modifier has been applied");
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
@@ -2118,7 +2114,6 @@ typedef struct ThickFace {
static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
{
-
const ThickFace *tf_a = (ThickFace *)tf_a_p;
const ThickFace *tf_b = (ThickFace *)tf_b_p;
@@ -2412,17 +2407,17 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* Depsgraph refresh functions are called here. */
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
- ED_uvedit_pack_islands_multi(scene,
- objects_changed,
- object_changed_len,
- NULL,
- &(struct UVPackIsland_Params){
- .rotate = true,
- .only_selected_uvs = only_selected_uvs,
- .only_selected_faces = true,
- .correct_aspect = correct_aspect,
- .use_seams = true,
- });
+
+ const struct UVPackIsland_Params params = {
+ .rotate = true,
+ .only_selected_uvs = only_selected_uvs,
+ .only_selected_faces = true,
+ .correct_aspect = correct_aspect,
+ .use_seams = true,
+ .margin_method = RNA_enum_get(op->ptr, "margin_method"),
+ .margin = RNA_float_get(op->ptr, "island_margin"),
+ };
+ ED_uvedit_pack_islands_multi(scene, objects_changed, object_changed_len, NULL, NULL, &params);
/* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
const bool per_face_aspect = false;
@@ -2464,6 +2459,8 @@ void UV_OT_smart_project(wmOperatorType *ot)
DEG2RADF(89.0f));
RNA_def_property_float_default(prop, DEG2RADF(66.0f));
+ RNA_def_enum(
+ ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", "");
RNA_def_float(ot->srna,
"island_margin",
0.0f,
@@ -3161,13 +3158,24 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
.calc_face_normal = true,
.calc_vert_normal = true,
}));
- /* select all uv loops first - pack parameters needs this to make sure charts are registered */
+ /* Select all UVs for cube_project. */
ED_uvedit_select_all(bm);
/* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */
uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, NULL);
- /* Set the margin really quickly before the packing operation. */
- scene->toolsettings->uvcalc_margin = 0.001f;
- uvedit_pack_islands(scene, ob, bm);
+
+ /* Pack UVs. */
+ const struct UVPackIsland_Params params = {
+ .rotate = true,
+ .only_selected_uvs = false,
+ .only_selected_faces = false,
+ .correct_aspect = false,
+ .use_seams = true,
+ .margin_method = ED_UVPACK_MARGIN_SCALED,
+ .margin = 0.001f,
+ };
+ ED_uvedit_pack_islands_multi(scene, &ob, 1, &bm, NULL, &params);
+
+ /* Write back from BMesh to Mesh. */
BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm);