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:
authorJacques Lucke <jacques@blender.org>2021-09-09 18:45:46 +0300
committerJacques Lucke <jacques@blender.org>2021-09-09 18:45:46 +0300
commitbcae5507b83ef19acf409fa80c5b8c060f58b0f3 (patch)
treeabf4a2d43e8d00c7d55c94c5adec2551ae7a6fac
parent2920a569b527c3543dd393a96bca2362ee04feef (diff)
parent29704854dfd7940409edf4c9f6709f3f30a3595a (diff)
Merge branch 'temp-geometry-nodes-fields' into parallel-multi-function
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py6
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py3
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/nodeitems_builtins.py14
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h5
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/intern/brush.c20
-rw-r--r--source/blender/blenkernel/intern/image.c67
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c222
-rw-r--r--source/blender/blenkernel/intern/lib_id.c18
-rw-r--r--source/blender/blenkernel/intern/object.c28
-rw-r--r--source/blender/blenloader/intern/versioning_290.c27
-rw-r--r--source/blender/blenloader/intern/versioning_300.c27
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc28
-rw-r--r--source/blender/blenloader/intern/versioning_common.h6
-rw-r--r--source/blender/draw/DRW_engine.h1
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c75
-rw-r--r--source/blender/draw/intern/DRW_render.h1
-rw-r--r--source/blender/draw/intern/draw_manager.c7
-rw-r--r--source/blender/draw/intern/draw_manager.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h10
-rw-r--r--source/blender/editors/object/object_relations.c20
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c46
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c402
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c62
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c25
-rw-r--r--source/blender/editors/transform/transform_convert_action.c20
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c2
-rw-r--r--source/blender/functions/FN_field.hh20
-rw-r--r--source/blender/functions/FN_field_cpp_type.hh3
-rw-r--r--source/blender/functions/intern/field.cc48
-rw-r--r--source/blender/io/usd/intern/usd_reader_instance.cc64
-rw-r--r--source/blender/io/usd/intern/usd_reader_instance.h47
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc2
-rw-r--r--source/blender/makesdna/DNA_image_types.h36
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc86
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c15
47 files changed, 782 insertions, 713 deletions
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 6a9306c2eab..44b77ab2aac 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -2606,8 +2606,7 @@ def km_sequencer(params):
for i in range(10)
)
),
- ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'},
- {"properties": [("deselect_all", True)]}),
+ ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
{"properties": [("extend", True)]}),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "alt": True},
@@ -6997,8 +6996,7 @@ def km_sequencer_editor_tool_select(params):
"Sequencer Tool: Select",
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
{"items": [
- ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'},
- {"properties": [("deselect_all", not params.legacy)]}),
+ ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
*_template_items_change_frame(params),
]},
)
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index dba94d71a43..dbe351eb10c 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -1814,8 +1814,7 @@ def km_sequencer(params):
for i in range(10)
)
),
- ("sequencer.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
- {"properties": [("deselect_all", True)]}),
+ ("sequencer.select", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("sequencer.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("extend", True)]}),
("sequencer.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 1ac19d020d8..0d1cbc424d7 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2254,6 +2254,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
+ ({"property": "use_geometry_nodes_fields"}, "T91274"),
),
)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index b2aefd63a78..114e654e22b 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -180,6 +180,10 @@ def object_eevee_cycles_shader_nodes_poll(context):
eevee_cycles_shader_nodes_poll(context))
+def geometry_nodes_fields_poll(context):
+ return context.preferences.experimental.use_geometry_nodes_fields
+
+
# All standard node categories currently used in nodes.
shader_node_categories = [
@@ -478,7 +482,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
- NodeItem("GeometryNodeAttributeCapture"),
+ NodeItem("GeometryNodeAttributeCapture", poll=geometry_nodes_fields_poll),
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
@@ -535,7 +539,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeJoinGeometry"),
NodeItem("GeometryNodeSeparateComponents"),
NodeItem("GeometryNodeRaycast"),
- NodeItem("GeometryNodeSetPosition"),
+ NodeItem("GeometryNodeSetPosition", poll=geometry_nodes_fields_poll),
]),
GeometryNodeCategory("GEO_INPUT", "Input", items=[
NodeItem("GeometryNodeObjectInfo"),
@@ -546,9 +550,9 @@ geometry_node_categories = [
NodeItem("FunctionNodeInputVector"),
NodeItem("GeometryNodeInputMaterial"),
NodeItem("GeometryNodeIsViewport"),
- NodeItem("GeometryNodeInputPosition"),
- NodeItem("GeometryNodeInputIndex"),
- NodeItem("GeometryNodeInputNormal"),
+ NodeItem("GeometryNodeInputPosition", poll=geometry_nodes_fields_poll),
+ NodeItem("GeometryNodeInputIndex", poll=geometry_nodes_fields_poll),
+ NodeItem("GeometryNodeInputNormal", poll=geometry_nodes_fields_poll),
]),
GeometryNodeCategory("GEO_MATERIAL", "Material", items=[
NodeItem("GeometryNodeMaterialAssign"),
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index a50faedcc3c..7fa21cc0656 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -237,6 +237,11 @@ enum {
/** Making that ID local is part of making local a whole library. */
LIB_ID_MAKELOCAL_FULL_LIBRARY = 1 << 0,
+ /** In case caller code already knows this ID should be made local without copying. */
+ LIB_ID_MAKELOCAL_FORCE_LOCAL = 1 << 1,
+ /** In case caller code already knows this ID should be made local using copying. */
+ LIB_ID_MAKELOCAL_FORCE_COPY = 1 << 2,
+
/* Special type-specific options. */
/** For Objects, do not clear the proxy pointers while making the data-block local. */
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 31b3cd66cbb..0e153c5a82a 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -463,6 +463,8 @@ void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_d
struct PartEff;
struct PartEff *BKE_object_do_version_give_parteff_245(struct Object *ob);
+bool BKE_object_supports_material_slots(struct Object *ob);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index d60ef28efda..56c22df3b02 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -142,8 +142,16 @@ static void brush_free_data(ID *id)
static void brush_make_local(Main *bmain, ID *id, const int flags)
{
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
Brush *brush = (Brush *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
+ const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
+ const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
+ BLI_assert(force_copy == false || force_copy != force_local);
+
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
@@ -151,19 +159,17 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
* - mixed: make copy
*/
- if (!ID_IS_LINKED(brush)) {
- return;
- }
-
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
BKE_lib_id_make_local(bmain, &brush->clone.image->id, false, 0);
}
- BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
+ if (!force_local && !force_copy) {
+ BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
+ }
- if (lib_local || is_local) {
- if (!is_lib) {
+ if (lib_local || is_local || force_copy || force_local) {
+ if (!is_lib || force_local) {
BKE_lib_id_clear_library_data(bmain, &brush->id);
BKE_lib_id_expand_local(bmain, &brush->id);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index d87290e1eb4..33f007c6dee 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -155,7 +155,9 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- image_dst->gputexture[i][eye] = NULL;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ image_dst->gputexture[i][eye][resolution] = NULL;
+ }
}
}
@@ -208,9 +210,11 @@ static void image_foreach_cache(ID *id,
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
- key.offset_in_ID = offsetof(Image, gputexture[a][eye]);
- key.cache_v = image->gputexture[a][eye];
- function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ key.offset_in_ID = offsetof(Image, gputexture[a][eye][resolution]);
+ key.cache_v = image->gputexture[a][eye];
+ function_callback(id, &key, (void **)&image->gputexture[a][eye][resolution], 0, user_data);
+ }
}
}
@@ -239,7 +243,9 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres
BLI_listbase_clear(&ima->gpu_refresh_areas);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- ima->gputexture[i][j] = NULL;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ ima->gputexture[i][j][resolution] = NULL;
+ }
}
}
@@ -677,8 +683,10 @@ bool BKE_image_has_opengl_texture(Image *ima)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye] != NULL) {
- return true;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ if (ima->gputexture[i][eye][resolution] != NULL) {
+ return true;
+ }
}
}
}
@@ -3531,9 +3539,11 @@ static void image_free_tile(Image *ima, ImageTile *tile)
}
for (int eye = 0; eye < 2; eye++) {
- if (ima->gputexture[i][eye] != NULL) {
- GPU_texture_free(ima->gputexture[i][eye]);
- ima->gputexture[i][eye] = NULL;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ if (ima->gputexture[i][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[i][eye][resolution]);
+ ima->gputexture[i][eye][resolution] = NULL;
+ }
}
}
}
@@ -3801,14 +3811,16 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
}
for (int eye = 0; eye < 2; eye++) {
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = NULL;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = NULL;
+ }
}
}
@@ -3863,14 +3875,17 @@ void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_nu
}
for (int eye = 0; eye < 2; eye++) {
- /* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
- ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL;
- }
- if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
- ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution] = NULL;
+ }
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye][resolution] = NULL;
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
index d179dd40c33..9712e912bed 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -49,6 +49,7 @@
/* Prototypes. */
static void gpu_free_unused_buffers(void);
static void image_free_gpu(Image *ima, const bool immediate);
+static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
@@ -97,9 +98,11 @@ static int smaller_power_of_2_limit(int num, bool limit_gl_texture_size)
return power_of_2_min_i(GPU_texture_size_with_limit(num, limit_gl_texture_size));
}
-static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
+static GPUTexture *gpu_texture_create_tile_mapping(
+ Image *ima, const int multiview_eye, const eImageTextureResolution texture_resolution)
{
- GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
+ const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
+ GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
if (tilearray == NULL) {
return 0;
@@ -121,13 +124,14 @@ static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multivi
}
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int i = tile->tile_number - 1001;
- data[4 * i] = tile->runtime.tilearray_layer;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ data[4 * i] = tile_runtime->tilearray_layer;
float *tile_info = &data[4 * width + 4 * i];
- tile_info[0] = tile->runtime.tilearray_offset[0] / array_w;
- tile_info[1] = tile->runtime.tilearray_offset[1] / array_h;
- tile_info[2] = tile->runtime.tilearray_size[0] / array_w;
- tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
+ tile_info[0] = tile_runtime->tilearray_offset[0] / array_w;
+ tile_info[1] = tile_runtime->tilearray_offset[1] / array_h;
+ tile_info[2] = tile_runtime->tilearray_size[0] / array_w;
+ tile_info[3] = tile_runtime->tilearray_size[1] / array_h;
}
GPUTexture *tex = GPU_texture_create_1d_array(ima->id.name + 2, width, 2, 1, GPU_RGBA32F, data);
@@ -152,9 +156,12 @@ static int compare_packtile(const void *a, const void *b)
return tile_a->pack_score < tile_b->pack_score;
}
-static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
+static GPUTexture *gpu_texture_create_tile_array(Image *ima,
+ ImBuf *main_ibuf,
+ const eImageTextureResolution texture_resolution)
{
- const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0;
+ const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
+ const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
ListBase boxes = {NULL};
@@ -200,14 +207,15 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ int *tileoffset = tile_runtime->tilearray_offset;
+ int *tilesize = tile_runtime->tilearray_size;
tileoffset[0] = packtile->boxpack.x;
tileoffset[1] = packtile->boxpack.y;
tilesize[0] = packtile->boxpack.w;
tilesize[1] = packtile->boxpack.h;
- tile->runtime.tilearray_layer = arraylayers;
+ tile_runtime->tilearray_layer = arraylayers;
}
BLI_freelistN(&packed);
@@ -221,9 +229,10 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
/* Upload each tile one by one. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- int tilelayer = tile->runtime.tilearray_layer;
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ int tilelayer = tile_runtime->tilearray_layer;
+ int *tileoffset = tile_runtime->tilearray_offset;
+ int *tilesize = tile_runtime->tilearray_size;
if (tilesize[0] == 0 || tilesize[1] == 0) {
continue;
@@ -268,16 +277,33 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
/** \name Regular gpu texture
* \{ */
+static bool image_max_resolution_texture_fits_in_limited_scale(Image *ima,
+ eGPUTextureTarget textarget,
+ const int multiview_eye)
+{
+ BLI_assert_msg(U.glreslimit != 0,
+ "limited scale function called without limited scale being set.");
+ GPUTexture *max_resolution_texture =
+ ima->gputexture[textarget][multiview_eye][IMA_TEXTURE_RESOLUTION_FULL];
+ if (max_resolution_texture && GPU_texture_width(max_resolution_texture) <= U.glreslimit &&
+ GPU_texture_height(max_resolution_texture) <= U.glreslimit) {
+ return true;
+ }
+ return false;
+}
+
static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
eGPUTextureTarget textarget,
- const int multiview_eye)
+ const int multiview_eye,
+ const eImageTextureResolution texture_resolution)
{
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
BLI_assert(in_range);
BLI_assert(multiview_eye == 0 || multiview_eye == 1);
+ const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
if (in_range) {
- return &(ima->gputexture[textarget][multiview_eye]);
+ return &(ima->gputexture[textarget][multiview_eye][resolution]);
}
return NULL;
}
@@ -296,6 +322,21 @@ static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
}
}
+static void image_update_reusable_textures(Image *ima,
+ eGPUTextureTarget textarget,
+ const int multiview_eye)
+{
+ if ((ima->gpuflag & IMA_GPU_HAS_LIMITED_SCALE_TEXTURES) == 0) {
+ return;
+ }
+
+ if (ELEM(textarget, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
+ if (image_max_resolution_texture_fits_in_limited_scale(ima, textarget, multiview_eye)) {
+ image_free_gpu_limited_scale(ima);
+ }
+ }
+}
+
static GPUTexture *image_get_gpu_texture(Image *ima,
ImageUser *iuser,
ImBuf *ibuf,
@@ -315,24 +356,17 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
short requested_pass = iuser ? iuser->pass : 0;
short requested_layer = iuser ? iuser->layer : 0;
short requested_view = iuser ? iuser->multi_index : 0;
- const bool limit_resolution = U.glreslimit != 0 &&
- ((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == NULL));
- short requested_gpu_flags = limit_resolution ? 0 : IMA_GPU_MAX_RESOLUTION;
-#define GPU_FLAGS_TO_CHECK (IMA_GPU_MAX_RESOLUTION)
/* There is room for 2 multiview textures. When a higher number is requested we should always
* target the first view slot. This is fine as multi view images aren't used together. */
if (requested_view < 2) {
requested_view = 0;
}
if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer ||
- ima->gpu_view != requested_view ||
- ((ima->gpuflag & GPU_FLAGS_TO_CHECK) != requested_gpu_flags)) {
+ ima->gpu_view != requested_view) {
ima->gpu_pass = requested_pass;
ima->gpu_layer = requested_layer;
ima->gpu_view = requested_view;
- ima->gpuflag &= ~GPU_FLAGS_TO_CHECK;
- ima->gpuflag |= requested_gpu_flags | IMA_GPU_REFRESH;
+ ima->gpuflag |= IMA_GPU_REFRESH;
}
#undef GPU_FLAGS_TO_CHECK
@@ -369,7 +403,14 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
if (current_view >= 2) {
current_view = 0;
}
- GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
+ const bool limit_resolution = U.glreslimit != 0 &&
+ ((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
+ (iuser == NULL)) &&
+ ((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
+ const eImageTextureResolution texture_resolution = limit_resolution ?
+ IMA_TEXTURE_RESOLUTION_LIMITED :
+ IMA_TEXTURE_RESOLUTION_FULL;
+ GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view, texture_resolution);
if (*tex) {
return *tex;
}
@@ -392,22 +433,19 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
if (textarget == TEXTARGET_2D_ARRAY) {
- *tex = gpu_texture_create_tile_array(ima, ibuf_intern);
+ *tex = gpu_texture_create_tile_array(ima, ibuf_intern, texture_resolution);
}
else if (textarget == TEXTARGET_TILE_MAPPING) {
- *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
+ *tex = gpu_texture_create_tile_mapping(
+ ima, iuser ? iuser->multiview_eye : 0, texture_resolution);
}
else {
const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima,
ibuf_intern);
- const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0;
- *tex = IMB_create_gpu_texture(ima->id.name + 2,
- ibuf_intern,
- use_high_bitdepth,
- store_premultiplied,
- limit_gl_texture_size);
+ *tex = IMB_create_gpu_texture(
+ ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied, limit_resolution);
if (*tex) {
GPU_texture_wrap_mode(*tex, true, false);
@@ -425,6 +463,20 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
}
+ switch (texture_resolution) {
+ case IMA_TEXTURE_RESOLUTION_LIMITED:
+ ima->gpuflag |= IMA_GPU_HAS_LIMITED_SCALE_TEXTURES;
+ break;
+
+ case IMA_TEXTURE_RESOLUTION_FULL:
+ image_update_reusable_textures(ima, textarget, current_view);
+ break;
+
+ case IMA_TEXTURE_RESOLUTION_LEN:
+ BLI_assert_unreachable();
+ break;
+ }
+
/* if `ibuf` was given, we don't own the `ibuf_intern` */
if (ibuf == NULL) {
BKE_image_release_ibuf(ima, ibuf_intern, NULL);
@@ -497,22 +549,39 @@ static void image_free_gpu(Image *ima, const bool immediate)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye] != NULL) {
- if (immediate) {
- GPU_texture_free(ima->gputexture[i][eye]);
- }
- else {
- BLI_mutex_lock(&gpu_texture_queue_mutex);
- BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
- BLI_mutex_unlock(&gpu_texture_queue_mutex);
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (immediate) {
+ GPU_texture_free(ima->gputexture[i][eye][resolution]);
+ }
+ else {
+ BLI_mutex_lock(&gpu_texture_queue_mutex);
+ BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye][resolution]);
+ BLI_mutex_unlock(&gpu_texture_queue_mutex);
+ }
+
+ ima->gputexture[i][eye][resolution] = NULL;
}
+ }
+ }
+ }
+
+ ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
+}
- ima->gputexture[i][eye] = NULL;
+static void image_free_gpu_limited_scale(Image *ima)
+{
+ const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
+ for (int eye = 0; eye < 2; eye++) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (ima->gputexture[i][eye][resolution] != NULL) {
+ GPU_texture_free(ima->gputexture[i][eye][resolution]);
+ ima->gputexture[i][eye][resolution] = NULL;
}
}
}
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
}
void BKE_image_free_gputextures(Image *ima)
@@ -689,12 +758,21 @@ static void gpu_texture_update_unscaled(GPUTexture *tex,
GPU_unpack_row_length_set(0);
}
-static void gpu_texture_update_from_ibuf(
- GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
+static void gpu_texture_update_from_ibuf(GPUTexture *tex,
+ Image *ima,
+ ImBuf *ibuf,
+ ImageTile *tile,
+ int x,
+ int y,
+ int w,
+ int h,
+ eImageTextureResolution texture_resolution)
{
+ const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
if (tile != NULL) {
- int *tilesize = tile->runtime.tilearray_size;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
}
else {
@@ -758,9 +836,10 @@ static void gpu_texture_update_from_ibuf(
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
if (tile != NULL) {
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
- int tilelayer = tile->runtime.tilearray_layer;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ int *tileoffset = tile_runtime->tilearray_offset;
+ int *tilesize = tile_runtime->tilearray_size;
+ int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_scaled(
tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
}
@@ -772,8 +851,9 @@ static void gpu_texture_update_from_ibuf(
else {
/* Fast update at same resolution. */
if (tile != NULL) {
- int *tileoffset = tile->runtime.tilearray_offset;
- int tilelayer = tile->runtime.tilearray_layer;
+ ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
+ int *tileoffset = tile_runtime->tilearray_offset;
+ int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_unscaled(
tex, rect, rect_float, x, y, tilelayer, tileoffset, w, h, tex_stride, tex_offset);
}
@@ -804,16 +884,20 @@ static void gpu_texture_update_from_ibuf(
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
{
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
- /* Check if we need to update the main gputexture. */
- if (tex != NULL && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
- }
+ const int eye = 0;
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
+ eImageTextureResolution texture_resolution = resolution;
+ /* Check if we need to update the main gputexture. */
+ if (tex != NULL && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h, texture_resolution);
+ }
- /* Check if we need to update the array gputexture. */
- tex = ima->gputexture[TEXTARGET_2D_ARRAY][0];
- if (tex != NULL) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
+ if (tex != NULL) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
+ }
}
}
@@ -917,12 +1001,14 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
if (BKE_image_has_opengl_texture(ima)) {
if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
- for (int eye = 0; eye < 2; eye++) {
- for (int a = 0; a < TEXTARGET_COUNT; a++) {
- if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
- GPUTexture *tex = ima->gputexture[a][eye];
- if (tex != NULL) {
- GPU_texture_mipmap_mode(tex, mipmap, true);
+ for (int a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
+ for (int eye = 0; eye < 2; eye++) {
+ for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ GPUTexture *tex = ima->gputexture[a][eye][resolution];
+ if (tex != NULL) {
+ GPU_texture_mipmap_mode(tex, mipmap, true);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 11e9053df43..cd0c3635dac 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -406,7 +406,15 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
*/
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
{
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
+ const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
+ const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
+ BLI_assert(force_copy == false || force_copy != force_local);
+
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
@@ -416,14 +424,12 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
* we always want to localize, and we skip remapping (done later).
*/
- if (!ID_IS_LINKED(id)) {
- return;
+ if (!force_copy && !force_local) {
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
}
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- if (lib_local || is_local) {
- if (!is_lib) {
+ if (lib_local || is_local || force_copy || force_local) {
+ if (!is_lib || force_local) {
BKE_lib_id_clear_library_data(bmain, id);
BKE_lib_id_expand_local(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index bca1afbf101..d0d1db9b4f8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -324,9 +324,17 @@ static void object_free_data(ID *id)
static void object_make_local(Main *bmain, ID *id, const int flags)
{
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
Object *ob = (Object *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0;
+ const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
+ const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
+ BLI_assert(force_copy == false || force_copy != force_local);
+
bool is_local = false, is_lib = false;
/* - only lib users: do nothing (unless force_local is set)
@@ -336,14 +344,12 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
* we always want to localize, and we skip remapping (done later).
*/
- if (!ID_IS_LINKED(ob)) {
- return;
+ if (!force_local && !force_copy) {
+ BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
}
- BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
-
- if (lib_local || is_local) {
- if (!is_lib) {
+ if (lib_local || is_local || force_copy || force_local) {
+ if (!is_lib || force_local) {
BKE_lib_id_clear_library_data(bmain, &ob->id);
BKE_lib_id_expand_local(bmain, &ob->id);
if (clear_proxy) {
@@ -5743,6 +5749,14 @@ void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
ob->data = new_data;
ob->runtime.geometry_set_eval = NULL;
ob->runtime.data_eval = NULL;
- ob->runtime.bb->flag |= BOUNDBOX_DIRTY;
+ if (ob->runtime.bb != NULL) {
+ ob->runtime.bb->flag |= BOUNDBOX_DIRTY;
+ }
ob->id.py_instance = NULL;
}
+
+bool BKE_object_supports_material_slots(struct Object *ob)
+{
+ return ELEM(
+ ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_HAIR, OB_POINTCLOUD, OB_VOLUME);
+}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index b217850e119..cb7a8ad592a 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -829,33 +829,6 @@ static void do_versions_strip_cache_settings_recursive(const ListBase *seqbase)
}
}
-static void version_node_socket_name(bNodeTree *ntree,
- const int node_type,
- const char *old_name,
- const char *new_name)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == node_type) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (STREQ(socket->name, old_name)) {
- strcpy(socket->name, new_name);
- }
- if (STREQ(socket->identifier, old_name)) {
- strcpy(socket->identifier, new_name);
- }
- }
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- if (STREQ(socket->name, old_name)) {
- strcpy(socket->name, new_name);
- }
- if (STREQ(socket->identifier, old_name)) {
- strcpy(socket->identifier, new_name);
- }
- }
- }
- }
-}
-
static void version_node_join_geometry_for_multi_input_socket(bNodeTree *ntree)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 13577164f20..f050de6e6e9 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -526,33 +526,6 @@ static void version_switch_node_input_prefix(Main *bmain)
FOREACH_NODETREE_END;
}
-static void version_node_socket_name(bNodeTree *ntree,
- const int node_type,
- const char *old_name,
- const char *new_name)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == node_type) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (STREQ(socket->name, old_name)) {
- strcpy(socket->name, new_name);
- }
- if (STREQ(socket->identifier, old_name)) {
- strcpy(socket->identifier, new_name);
- }
- }
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- if (STREQ(socket->name, old_name)) {
- strcpy(socket->name, new_name);
- }
- if (STREQ(socket->identifier, old_name)) {
- strcpy(socket->identifier, new_name);
- }
- }
- }
- }
-}
-
static bool replace_bbone_len_scale_rnapath(char **p_old_path, int *p_index)
{
char *old_path = *p_old_path;
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 208c02b60d1..3f13d1ec12e 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -22,6 +22,7 @@
#include <cstring>
+#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "BLI_listbase.h"
@@ -85,3 +86,30 @@ ID *do_versions_rename_id(Main *bmain,
}
return id;
}
+
+void version_node_socket_name(bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (STREQ(socket->name, old_name)) {
+ BLI_strncpy(socket->name, new_name, sizeof(socket->name));
+ }
+ if (STREQ(socket->identifier, old_name)) {
+ BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
+ }
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ if (STREQ(socket->name, old_name)) {
+ BLI_strncpy(socket->name, new_name, sizeof(socket->name));
+ }
+ if (STREQ(socket->identifier, old_name)) {
+ BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 47e0b74a3e4..c1fe2b591cd 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -23,6 +23,7 @@
struct ARegion;
struct ListBase;
struct Main;
+struct bNodeTree;
#ifdef __cplusplus
extern "C" {
@@ -38,6 +39,11 @@ ID *do_versions_rename_id(Main *bmain,
const char *name_src,
const char *name_dst);
+void version_node_socket_name(struct bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 8a35ab2aeb9..a125a13eaf9 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -110,6 +110,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
bool use_obedit_skip,
bool draw_surface,
bool use_nearest,
+ const bool do_material_sub_selection,
const struct rcti *rect,
DRW_SelectPassFn select_pass_fn,
void *select_pass_user_data,
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index c120df7e897..87f5c6f5857 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -25,9 +25,12 @@
#include "DRW_render.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BLI_alloca.h"
+
#include "DNA_particle_types.h"
#include "GPU_shader.h"
@@ -80,6 +83,7 @@ typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp[2];
DRWShadingGroup *depth_shgrp_cull[2];
DRWShadingGroup *depth_hair_shgrp[2];
+ bool use_material_slot_selection;
} BASIC_PrivateData; /* Transient data */
/* Functions */
@@ -131,6 +135,8 @@ static void basic_cache_init(void *vedata)
stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
+ stl->g_data->use_material_slot_selection = DRW_state_is_material_select();
+
/* Twice for normal and in front objects. */
for (int i = 0; i < 2; i++) {
DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0;
@@ -155,6 +161,38 @@ static void basic_cache_init(void *vedata)
}
}
+/* TODO(fclem): DRW_cache_object_surface_material_get needs a refactor to allow passing NULL
+ * instead of gpumat_array. Avoiding all this boilerplate code. */
+static struct GPUBatch **basic_object_surface_material_get(Object *ob)
+{
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
+
+ return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
+}
+
+static void basic_cache_populate_particles(void *vedata, Object *ob)
+{
+ const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+ for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as == PART_DRAW_PATH) {
+ struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
+ if (stl->g_data->use_material_slot_selection) {
+ const short material_slot = part->omat;
+ DRW_select_load_id(ob->runtime.select_id | (material_slot << 16));
+ }
+ DRW_shgroup_call(stl->g_data->depth_hair_shgrp[do_in_front], hairs, NULL);
+ }
+ }
+}
+
static void basic_cache_populate(void *vedata, Object *ob)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
@@ -165,24 +203,13 @@ static void basic_cache_populate(void *vedata, Object *ob)
return;
}
- bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
-
const DRWContextState *draw_ctx = DRW_context_state_get();
if (ob != draw_ctx->object_edit) {
- for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
- ParticleSettings *part = psys->part;
- const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
- if (draw_as == PART_DRAW_PATH) {
- struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
- DRW_shgroup_call(stl->g_data->depth_hair_shgrp[do_in_front], hairs, NULL);
- }
- }
+ basic_cache_populate_particles(vedata, ob);
}
/* Make flat object selectable in ortho view if wireframe is enabled. */
+ const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
if ((draw_ctx->v3d->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
(draw_ctx->v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) {
int flat_axis = 0;
@@ -211,9 +238,25 @@ static void basic_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_sculpt(shgrp, ob, false, false);
}
else {
- struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
- if (geom) {
- DRW_shgroup_call(shgrp, geom, ob);
+ if (stl->g_data->use_material_slot_selection && BKE_object_supports_material_slots(ob)) {
+ struct GPUBatch **geoms = basic_object_surface_material_get(ob);
+ if (geoms) {
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ for (int i = 0; i < materials_len; i++) {
+ if (geoms[i] == NULL) {
+ continue;
+ }
+ const short material_slot_select_id = i + 1;
+ DRW_select_load_id(ob->runtime.select_id | (material_slot_select_id << 16));
+ DRW_shgroup_call(shgrp, geoms[i], ob);
+ }
+ }
+ }
+ else {
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRW_shgroup_call(shgrp, geom, ob);
+ }
}
}
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 6639a100af9..660a4adaf51 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -731,6 +731,7 @@ void DRW_select_load_id(uint id);
/* Draw State */
bool DRW_state_is_fbo(void);
bool DRW_state_is_select(void);
+bool DRW_state_is_material_select(void);
bool DRW_state_is_depth(void);
bool DRW_state_is_image_render(void);
bool DRW_state_is_scene_render(void);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 9590a4aa7ee..aca645acc09 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -2232,6 +2232,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
bool use_obedit_skip,
bool draw_surface,
bool UNUSED(use_nearest),
+ const bool do_material_sub_selection,
const rcti *rect,
DRW_SelectPassFn select_pass_fn,
void *select_pass_user_data,
@@ -2299,6 +2300,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DST.viewport = viewport;
DST.options.is_select = true;
+ DST.options.is_material_select = do_material_sub_selection;
drw_task_graph_init();
/* Get list of enabled engines */
if (use_obedit) {
@@ -2776,6 +2778,11 @@ bool DRW_state_is_select(void)
return DST.options.is_select;
}
+bool DRW_state_is_material_select(void)
+{
+ return DST.options.is_material_select;
+}
+
bool DRW_state_is_depth(void)
{
return DST.options.is_depth;
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 1747ca752c7..c09126c98ef 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -553,6 +553,7 @@ typedef struct DRWManager {
struct {
uint is_select : 1;
+ uint is_material_select : 1;
uint is_depth : 1;
uint is_image_render : 1;
uint is_scene_render : 1;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 2c958d282f9..cf8dcbd7995 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -566,6 +566,13 @@ eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *sce
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+int view3d_opengl_select_ex(struct ViewContext *vc,
+ unsigned int *buffer,
+ unsigned int bufsize,
+ const struct rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -638,6 +645,9 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index ec72ff11683..75269dffec8 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2729,25 +2729,26 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
if (ob == NULL) {
return BLI_strdup("");
}
+ mat_slot = max_ii(mat_slot, 1);
char name[MAX_ID_NAME - 2];
RNA_string_get(properties, "name", name);
- int active_mat_slot = max_ii(ob->actcol, 1);
- Material *prev_mat = BKE_object_material_get(ob, active_mat_slot);
+ Material *prev_mat = BKE_object_material_get(ob, mat_slot);
char *result;
if (prev_mat) {
const char *tooltip = TIP_("Drop %s on %s (slot %d, replacing %s)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot, prev_mat->id.name + 2);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot, prev_mat->id.name + 2);
}
else {
const char *tooltip = TIP_("Drop %s on %s (slot %d)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot);
}
return result;
}
@@ -2755,7 +2756,10 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
+ mat_slot = max_ii(mat_slot, 1);
+
Material *ma;
char name[MAX_ID_NAME - 2];
@@ -2765,9 +2769,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
- const short active_mat_slot = ob->actcol;
-
- BKE_object_material_assign(CTX_data_main(C), ob, ma, active_mat_slot, BKE_MAT_ASSIGN_USERPREF);
+ BKE_object_material_assign(CTX_data_main(C), ob, ma, mat_slot, BKE_MAT_ASSIGN_USERPREF);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 10629caa8b0..f04336cab84 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -41,6 +41,7 @@
#include "ED_keyframes_edit.h"
#include "ED_numinput.h"
#include "ED_screen.h"
+#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -94,6 +95,8 @@ typedef struct tDecimateGraphOp {
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
+ struct tSlider *slider;
+
NumInput num;
} tDecimateGraphOp;
@@ -161,6 +164,8 @@ static void decimate_exit(bContext *C, wmOperator *op)
ScrArea *area = dgo->area;
LinkData *link;
+ ED_slider_destroy(C, dgo->slider);
+
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
tBeztCopyData *copy = link->data;
MEM_freeN(copy->bezt);
@@ -178,11 +183,14 @@ static void decimate_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
-/* Draw a percentage indicator in header. */
-static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Decimate Keyframes"));
@@ -194,23 +202,10 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
- float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
- ED_area_status_text(dgo->area, status_str);
-}
-
-/* Calculate percentage based on position of mouse (we only use x-axis for now.
- * Since this is more convenient for users to do), and store new percentage value.
- */
-static void decimate_mouse_update_percentage(tDecimateGraphOp *dgo,
- wmOperator *op,
- const wmEvent *event)
-{
- float percentage = (event->x - dgo->region->winrct.xmin) / ((float)dgo->region->winx);
- RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
+ ED_workspace_status_text(C, status_str);
}
static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -234,10 +229,11 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
dgo->area = CTX_wm_area(C);
dgo->region = CTX_wm_region(C);
- /* Initialize percentage so that it will have the correct value before the first mouse move. */
- decimate_mouse_update_percentage(dgo, op, event);
+ dgo->slider = ED_slider_create(C);
+ ED_slider_init(dgo->slider, event);
+ ED_slider_allow_overshoot_set(dgo->slider, false);
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Construct a list with the original bezt arrays so we can restore them during modal operation.
*/
@@ -300,13 +296,14 @@ static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
* (e.g. pressing a key or moving the mouse). */
tDecimateGraphOp *dgo = op->customdata;
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Reset keyframe data (so we get back to the original state). */
decimate_reset_bezts(dgo);
/* Apply... */
- float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+ float remove_ratio = ED_slider_factor_get(dgo->slider);
+ RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio);
/* We don't want to limit the decimation to a certain error margin. */
const float error_sq_max = FLT_MAX;
decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max);
@@ -323,6 +320,8 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
const bool has_numinput = hasNumInput(&dgo->num);
+ ED_slider_modal(dgo->slider, event);
+
switch (event->type) {
case LEFTMOUSE: /* Confirm */
case EVT_RETKEY:
@@ -353,9 +352,6 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
case MOUSEMOVE: /* Calculate new position. */
{
if (has_numinput == false) {
- /* Update percentage based on position of mouse. */
- decimate_mouse_update_percentage(dgo, op, event);
-
/* Update pose to reflect the new values. */
graphkeys_decimate_modal_update(C, op);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 4c938a412d2..80d3e2cbdaa 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -504,238 +504,245 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
/** \name Select Operator
* \{ */
-static int sequencer_select_exec(bContext *C, wmOperator *op)
+static void sequencer_select_set_active(Scene *scene, Sequence *seq)
{
- View2D *v2d = UI_view2d_fromcontext(C);
- Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
- const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
- bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
- bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- int mval[2];
- int ret_value = OPERATOR_CANCELLED;
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
-
- Sequence *seq, *neighbor, *act_orig;
- int hand, sel_side;
+ SEQ_select_active_set(scene, seq);
- if (ed == NULL) {
- return OPERATOR_CANCELLED;
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
+ }
}
-
- if (extend) {
- wait_to_deselect_others = false;
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
+ }
}
+ recurs_sel_seq(seq);
+}
- seq = find_nearest_seq(scene, v2d, &hand, mval);
+static void sequencer_select_do_updates(bContext *C, Scene *scene)
+{
+ ED_outliner_select_sync_from_sequence_tag(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+}
- /* XXX: not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip. */
- if (seq && linked_time) {
- side_of_frame = false;
- }
+static void sequencer_select_side_of_frame(const bContext *C,
+ const View2D *v2d,
+ const int mval[2],
+ Scene *scene)
+{
+ Editing *ed = SEQ_editing_get(scene);
- /* Select left, right or overlapping the current frame. */
- if (side_of_frame) {
- /* Use different logic for this. */
- if (extend == false) {
- ED_sequencer_deselect_all(scene);
+ const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
+ if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
+ ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
+ /* Select left or right. */
+ seq_iter->flag |= SELECT;
+ recurs_sel_seq(seq_iter);
}
+ }
- const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ {
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
+ TimeMarker *tmarker;
- LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
- ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
- /* Select left or right. */
- seq_iter->flag |= SELECT;
- recurs_sel_seq(seq_iter);
+ for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
+ if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
+ ((x >= CFRA) && (tmarker->frame >= CFRA))) {
+ tmarker->flag |= SELECT;
+ }
+ else {
+ tmarker->flag &= ~SELECT;
+ }
}
}
+ }
+}
- {
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
- TimeMarker *tmarker;
+static void sequencer_select_linked_handle(const bContext *C,
+ Sequence *seq,
+ const int handle_clicked)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ if (!ELEM(handle_clicked, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
+ /* First click selects the strip and its adjacent handles (if valid).
+ * Second click selects the strip,
+ * both of its handles and its adjacent handles (if valid). */
+ const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+ seq->flag &= ~SEQ_ALLSEL;
+ seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
+ select_surrounding_handles(scene, seq);
+ }
+ else {
+ /* Always select the strip under the cursor. */
+ seq->flag |= SELECT;
- for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
- ((x >= CFRA) && (tmarker->frame >= CFRA))) {
- tmarker->flag |= SELECT;
+ /* First click selects adjacent handles on that side.
+ * Second click selects all strips in that direction.
+ * If there are no adjacent strips, it just selects all in that direction.
+ */
+ int sel_side = handle_clicked;
+ Sequence *neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
+ if (neighbor) {
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
}
else {
- tmarker->flag &= ~SELECT;
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
}
- }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ }
+ else {
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ break;
}
}
+ else {
- ret_value = OPERATOR_FINISHED;
+ select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ }
}
- else {
- act_orig = ed->act_seq;
-
- if (seq) {
- /* Are we trying to select a handle that's already selected? */
- const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
- ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
-
- if (wait_to_deselect_others && (seq->flag & SELECT) &&
- (hand == SEQ_SIDE_NONE || handle_selected)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else if (!extend && !linked_handle) {
- ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
- }
- else {
- ret_value = OPERATOR_FINISHED;
- }
-
- SEQ_select_active_set(scene, seq);
+}
- if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
- if (seq->strip) {
- BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
- }
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->strip) {
- BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
- }
- }
+static bool element_already_selected(const Sequence *seq, const int handle_clicked)
+{
+ const bool handle_already_selected = ((handle_clicked == SEQ_SIDE_LEFT) &&
+ (seq->flag & SEQ_LEFTSEL)) ||
+ ((handle_clicked == SEQ_SIDE_RIGHT) &&
+ (seq->flag & SEQ_RIGHTSEL));
+ return ((seq->flag & SELECT) && handle_clicked == SEQ_SIDE_NONE) || handle_already_selected;
+}
- /* On Alt selection, select the strip and bordering handles. */
- if (linked_handle) {
- if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
- /* First click selects the strip and its adjacent handles (if valid).
- * Second click selects the strip,
- * both of its handles and its adjacent handles (if valid). */
- const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+static void sequencer_select_strip_impl(const Editing *ed,
+ Sequence *seq,
+ const int handle_clicked,
+ const bool extend)
+{
+ /* Deselect strip. */
+ if (extend && (seq->flag & SELECT) && ed->act_seq == seq) {
+ switch (handle_clicked) {
+ case SEQ_SIDE_NONE:
+ seq->flag &= ~SEQ_ALLSEL;
+ break;
+ case SEQ_SIDE_LEFT:
+ seq->flag ^= SEQ_LEFTSEL;
+ break;
+ case SEQ_SIDE_RIGHT:
+ seq->flag ^= SEQ_RIGHTSEL;
+ break;
+ }
+ }
+ else { /* Select strip. */
+ seq->flag |= SELECT;
+ if (handle_clicked == SEQ_SIDE_LEFT) {
+ seq->flag |= SEQ_LEFTSEL;
+ }
+ if (handle_clicked == SEQ_SIDE_RIGHT) {
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ }
+}
- if (!extend) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag &= ~SEQ_ALLSEL;
- seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
- select_surrounding_handles(scene, seq);
- }
- else {
- /* Always select the strip under the cursor. */
- seq->flag |= SELECT;
+static int sequencer_select_exec(bContext *C, wmOperator *op)
+{
+ View2D *v2d = UI_view2d_fromcontext(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* First click selects adjacent handles on that side.
- * Second click selects all strips in that direction.
- * If there are no adjacent strips, it just selects all in that direction.
- */
- sel_side = hand;
- neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
- if (neighbor) {
- switch (sel_side) {
- case SEQ_SIDE_LEFT:
- if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_RIGHTSEL;
- seq->flag |= SEQ_LEFTSEL;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_LEFTSEL;
- seq->flag |= SEQ_RIGHTSEL;
- }
- break;
- }
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
- }
- }
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
- switch (hand) {
- case SEQ_SIDE_NONE:
- if (linked_handle == 0) {
- seq->flag &= ~SEQ_ALLSEL;
- }
- break;
- case SEQ_SIDE_LEFT:
- seq->flag ^= SEQ_LEFTSEL;
- break;
- case SEQ_SIDE_RIGHT:
- seq->flag ^= SEQ_RIGHTSEL;
- break;
- }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- seq->flag |= SELECT;
- if (hand == SEQ_SIDE_LEFT) {
- seq->flag |= SEQ_LEFTSEL;
- }
- if (hand == SEQ_SIDE_RIGHT) {
- seq->flag |= SEQ_RIGHTSEL;
- }
- }
- }
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
- recurs_sel_seq(seq);
+ int handle_clicked;
+ Sequence *seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
- if (linked_time) {
- select_linked_time(ed->seqbasep, seq);
- }
+ /* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
+ * therefore both properties can be true at the same time. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ }
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ select_linked_time(ed->seqbasep, seq);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
+ }
- BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
+ /* Select left, right or overlapping the current frame. */
+ if (RNA_boolean_get(op->ptr, "side_of_frame")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
}
- else if (deselect_all) {
+ sequencer_select_side_of_frame(C, v2d, mval, scene);
+ sequencer_select_do_updates(C, scene);
+ return OPERATOR_FINISHED;
+ }
+
+ /* On Alt selection, select the strip and bordering handles. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
+ if (!extend) {
ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
}
+ sequencer_select_linked_handle(C, seq, handle_clicked);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+ /* Clicking on already selected element falls on modal operation.
+ * All strips are deselected on mouse button release unless extend mode is used. */
+ if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !extend) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ int ret_value = OPERATOR_CANCELLED;
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
+ }
+
+ /* Nothing to select, but strips could be deselected. */
+ if (!seq) {
+ sequencer_select_do_updates(C, scene);
+ return ret_value;
+ }
+
+ /* Do actual selection. */
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ ret_value = OPERATOR_FINISHED;
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
return ret_value;
}
@@ -764,13 +771,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna,
"linked_handle",
false,
"Linked Handle",
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index e3f97dd1c63..ff98762e373 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1953,7 +1953,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
const int mval[2],
eV3DSelectObjectFilter select_filter,
bool do_nearest,
- bool do_nearest_xray_if_supported)
+ bool do_nearest_xray_if_supported,
+ const bool do_material_slot_selection)
{
rcti rect;
int hits15, hits9 = 0, hits5 = 0;
@@ -1972,7 +1973,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
view3d_opengl_select_cache_begin();
BLI_rcti_init_pt_radius(&rect, mval, 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ hits15 = view3d_opengl_select_ex(
+ vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, do_material_slot_selection);
if (hits15 == 1) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
goto finally;
@@ -2071,7 +2073,8 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
- int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
+ int hits = mixed_bones_object_selectbuffer(
+ vc, buffer, mval, select_filter, do_nearest, true, false);
return hits;
}
@@ -2088,12 +2091,14 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
int hits,
Base *startbase,
bool has_bones,
- bool do_nearest)
+ bool do_nearest,
+ int *r_sub_selection)
{
ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
int a;
+ int sub_selection_id = 0;
if (do_nearest) {
uint min = 0xFFFFFFFF;
@@ -2105,6 +2110,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2118,6 +2124,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2184,11 +2191,16 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
}
+ if (basact && r_sub_selection) {
+ *r_sub_selection = sub_selection_id;
+ }
+
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
-Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
+ const int mval[2],
+ int *r_material_slot)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
@@ -2202,18 +2214,30 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
+ const bool do_material_slot_selection = r_material_slot != NULL;
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
+ &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false, do_material_slot_selection);
if (hits > 0) {
- const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(
- &vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
+ const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
+ basact = mouse_select_eval_buffer(&vc,
+ buffer,
+ hits,
+ vc.view_layer->object_bases.first,
+ has_bones,
+ do_nearest,
+ r_material_slot);
}
return basact;
}
+/* mval comes from event->mval, only use within region handlers */
+Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+{
+ return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
+}
+
Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
{
Base *base = ED_view3d_give_base_under_cursor(C, mval);
@@ -2223,6 +2247,17 @@ Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
return NULL;
}
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot)
+{
+ Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot);
+ if (base) {
+ return base->object;
+ }
+ return NULL;
+}
+
bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
{
return ED_view3d_give_object_under_cursor(C, mval) != NULL;
@@ -2374,7 +2409,8 @@ static bool ed_object_select_pick(bContext *C,
}
}
else {
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
+ basact = mouse_select_eval_buffer(
+ &vc, buffer, hits, startbase, has_bones, do_nearest, NULL);
}
if (has_bones && basact) {
@@ -2436,7 +2472,7 @@ static bool ed_object_select_pick(bContext *C,
if (!changed) {
/* fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest, NULL);
}
}
}
@@ -2677,7 +2713,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
uint buffer[MAXPICKBUF];
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true);
+ &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true, false);
retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
}
if (!retval) {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 86a610f8dd9..b9f3706b084 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -964,12 +964,13 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-int view3d_opengl_select(ViewContext *vc,
- uint *buffer,
- uint bufsize,
- const rcti *input,
- eV3DSelectMode select_mode,
- eV3DSelectObjectFilter select_filter)
+int view3d_opengl_select_ex(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection)
{
struct bThemeState theme_state;
const wmWindowManager *wm = CTX_wm_manager(vc->C);
@@ -1119,6 +1120,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1149,6 +1151,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1178,6 +1181,16 @@ finally:
return hits;
}
+int view3d_opengl_select(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter)
+{
+ return view3d_opengl_select_ex(vc, buffer, bufsize, input, select_mode, select_filter, false);
+}
+
int view3d_opengl_select_with_id_filter(ViewContext *vc,
uint *buffer,
uint bufsize,
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 075db30fa61..a6658ae00a3 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -51,7 +51,10 @@
/* helper struct for gp-frame transforms */
typedef struct tGPFtransdata {
- float val; /* where transdata writes transform */
+ union {
+ float val; /* where transdata writes transform */
+ float loc[3]; /* #td->val and #td->loc share the same pointer. */
+ };
int *sdata; /* pointer to gpf->framenum */
} tGPFtransdata;
@@ -245,8 +248,8 @@ static int GPLayerToTransData(TransData *td,
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
- td->val = td->loc = &tfd->val; /* XXX: It's not a 3d array. */
- td->ival = td->iloc[0] = (float)gpf->framenum;
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
@@ -279,16 +282,15 @@ static int MaskLayerToTransData(TransData *td,
masklay_shape = masklay_shape->next) {
if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)masklay_shape->frame;
+ tfd->val = (float)masklay_shape->frame;
+ tfd->sdata = &masklay_shape->frame;
+
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
- tfd->val = (float)masklay_shape->frame;
- tfd->sdata = &masklay_shape->frame;
-
/* advance td now */
td++;
tfd++;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 9f5e74db501..0dfb229191c 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -791,7 +791,7 @@ static void restoreElement(TransData *td)
{
transdata_restore_basic((TransDataBasic *)td);
- if (td->val) {
+ if (td->val && td->val != td->loc) {
*td->val = td->ival;
}
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index a54149912a9..e82a00bcc77 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -260,7 +260,7 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
SeqCollection *snap_sources = SEQ_query_selected_strips(seqbase);
SeqCollection *snap_targets = query_snap_targets(t, snap_sources);
- if (SEQ_collection_len(snap_sources) == 0 || SEQ_collection_len(snap_targets) == 0) {
+ if (SEQ_collection_len(snap_sources) == 0) {
SEQ_collection_free(snap_targets);
SEQ_collection_free(snap_sources);
MEM_freeN(snap_data);
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 07859565a06..25188531580 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -27,8 +27,8 @@
*
* Fields can be build, composed and evaluated at run-time. They are stored in a directed tree
* graph data structure, whereby each node is a #FieldNode and edges are dependencies. A #FieldNode
- * has an arbitrary number of inputs and at least one output. A #Field references a specific output
- * of a #FieldNode. The inputs of a #FieldNode are other fields.
+ * has an arbitrary number of inputs and at least one output and a #Field references a specific
+ * output of a #FieldNode. The inputs of a #FieldNode are other fields.
*
* There are two different types of field nodes:
* - #FieldInput: Has no input and exactly one output. It represents an input to the entire field
@@ -319,7 +319,7 @@ class FieldEvaluator : NonMovable, NonCopyable {
const FieldContext &context_;
const IndexMask mask_;
Vector<GField> fields_to_evaluate_;
- Vector<GVMutableArray *> dst_hints_;
+ Vector<GVMutableArray *> dst_varrays_;
Vector<const GVArray *> evaluated_varrays_;
Vector<OutputPointerInfo> output_pointer_infos_;
bool is_evaluated_ = false;
@@ -352,9 +352,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
/** Same as #add_with_destination but typed. */
template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst)
{
- GVMutableArray &generic_dst_hint = scope_.construct<GVMutableArray_For_VMutableArray<T>>(
- __func__, dst);
- return this->add_with_destination(GField(std::move(field)), generic_dst_hint);
+ GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(__func__, dst);
+ return this->add_with_destination(GField(std::move(field)), varray);
}
/**
@@ -373,9 +372,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
*/
template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
{
- GVMutableArray &generic_dst_hint = scope_.construct<GVMutableArray_For_MutableSpan<T>>(
- __func__, dst);
- return this->add_with_destination(std::move(field), generic_dst_hint);
+ GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(__func__, dst);
+ return this->add_with_destination(std::move(field), varray);
}
int add(GField field, const GVArray **varray_ptr);
@@ -389,7 +387,7 @@ class FieldEvaluator : NonMovable, NonCopyable {
template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_hints_.append(nullptr);
+ dst_varrays_.append(nullptr);
output_pointer_infos_.append(OutputPointerInfo{
varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) {
*(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(__func__, varray);
@@ -432,7 +430,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
const FieldContext &context,
- Span<GVMutableArray *> dst_hints = {});
+ Span<GVMutableArray *> dst_varrays = {});
/* --------------------------------------------------------------------
* Utility functions for simple field creation and evaluation.
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh
index b7eff8f8cf0..5e6f1b5a585 100644
--- a/source/blender/functions/FN_field_cpp_type.hh
+++ b/source/blender/functions/FN_field_cpp_type.hh
@@ -45,8 +45,7 @@ class FieldCPPType : public CPPType {
return field_type_;
}
- /* Ensure that a #GField and #Field<T> have the same layout, so pointers can be cast between the
- * two. */
+ /* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */
static_assert(sizeof(Field<int>) == sizeof(GField));
static_assert(sizeof(Field<int>) == sizeof(Field<std::string>));
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 7b35593ad75..06730a8b830 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -32,9 +32,9 @@ namespace blender::fn {
struct FieldTreeInfo {
/**
- * When fields are build, they only have references to the fields that they depend on. This map
- * allows traversal of fields in the opposite direction. So for every field it stores what other
- * fields directly depend on it.
+ * When fields are built, they only have references to the fields that they depend on. This map
+ * allows traversal of fields in the opposite direction. So for every field it stores the other
+ * fields that depend on it directly.
*/
MultiValueMap<GFieldRef, GFieldRef> field_users;
/**
@@ -113,7 +113,7 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info,
/* The varying fields are the ones that depend on inputs that are not constant. Therefore we
* start the tree search at the non-constant input fields and traverse through all fields that
- * depend on those. */
+ * depend on them. */
for (const int i : field_context_inputs.index_range()) {
const GVArray *varray = field_context_inputs[i];
if (varray->is_single()) {
@@ -260,29 +260,31 @@ struct PartiallyInitializedArray : NonCopyable, NonMovable {
* virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
* \param context: The context that the field is evaluated in. Used to retrieve data from each
* #FieldInput in the field network.
- * \param dst_hints: If provided, the computed data will be written into those virtual arrays
+ * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
* instead of into newly created ones. That allows making the computed data live longer than
* #scope and is more efficient when the data will be written into those virtual arrays
* later anyway.
- * \return The computed virtual arrays for each provided field. If #dst_hints is passed, the
+ * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
* provided virtual arrays are returned.
*/
Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
const FieldContext &context,
- Span<GVMutableArray *> dst_hints)
+ Span<GVMutableArray *> dst_varrays)
{
SCOPED_TIMER(__func__);
Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr);
+ const int array_size = mask.min_array_size();
- /* Destination hints are optional. Create a small utility method to access them. */
- auto get_dst_hint_if_available = [&](int index) -> GVMutableArray * {
- if (dst_hints.is_empty()) {
+ /* Destination arrays are optional. Create a small utility method to access them. */
+ auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * {
+ if (dst_varrays.is_empty()) {
return nullptr;
}
- return dst_hints[index];
+ BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size);
+ return dst_varrays[index];
};
/* Traverse the field tree and prepare some data that is used in later steps. */
@@ -329,8 +331,6 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
}
}
- const int array_size = mask.min_array_size();
-
/* Evaluate varying fields if necessary. */
if (!varying_fields_to_evaluate.is_empty()) {
/* Build the procedure for those fields. */
@@ -355,7 +355,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
const int out_index = varying_field_indices[i];
/* Try to get an existing virtual array that the result should be written into. */
- GVMutableArray *output_varray = get_dst_hint_if_available(out_index);
+ GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
void *buffer;
if (output_varray == nullptr || !output_varray->is_span()) {
/* Allocate a new buffer for the computed result. */
@@ -426,11 +426,11 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
procedure_executor.call(IndexRange(1), mf_params, mf_context);
}
- /* Copy data to destination hints if still necessary. In some cases the evaluation above has
+ /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has
* written the computed data in the right place already. */
- if (!dst_hints.is_empty()) {
+ if (!dst_varrays.is_empty()) {
for (const int out_index : fields_to_evaluate.index_range()) {
- GVMutableArray *output_varray = get_dst_hint_if_available(out_index);
+ GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
if (output_varray == nullptr) {
/* Caller did not provide a destination for this output. */
continue;
@@ -487,6 +487,7 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
/* If the selection is just a single value, it's best to avoid calling this
* function when constructing an IndexMask and use an IndexRange instead. */
BLI_assert(!selection.is_single());
+
Vector<int64_t> indices;
if (selection.is_span()) {
Span<bool> span = selection.get_internal_span();
@@ -509,22 +510,21 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_hints_.append(&dst);
+ dst_varrays_.append(&dst);
output_pointer_infos_.append({});
return field_index;
}
int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst)
{
- GVMutableArray &varray_dst_hint = scope_.construct<GVMutableArray_For_GMutableSpan>(__func__,
- dst);
- return this->add_with_destination(std::move(field), varray_dst_hint);
+ GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(__func__, dst);
+ return this->add_with_destination(std::move(field), varray);
}
int FieldEvaluator::add(GField field, const GVArray **varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_hints_.append(nullptr);
+ dst_varrays_.append(nullptr);
output_pointer_infos_.append(OutputPointerInfo{
varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) {
*(const GVArray **)dst = &varray;
@@ -535,7 +535,7 @@ int FieldEvaluator::add(GField field, const GVArray **varray_ptr)
int FieldEvaluator::add(GField field)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_hints_.append(nullptr);
+ dst_varrays_.append(nullptr);
output_pointer_infos_.append({});
return field_index;
}
@@ -547,7 +547,7 @@ void FieldEvaluator::evaluate()
for (const int i : fields_to_evaluate_.index_range()) {
fields[i] = fields_to_evaluate_[i];
}
- evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_hints_);
+ evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_varrays_);
BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
for (const int i : fields_to_evaluate_.index_range()) {
OutputPointerInfo &info = output_pointer_infos_[i];
diff --git a/source/blender/io/usd/intern/usd_reader_instance.cc b/source/blender/io/usd/intern/usd_reader_instance.cc
deleted file mode 100644
index e645b0237b9..00000000000
--- a/source/blender/io/usd/intern/usd_reader_instance.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2021 Blender Foundation.
- * All rights reserved.
- */
-
-#include "usd_reader_instance.h"
-
-#include "BKE_object.h"
-#include "DNA_object_types.h"
-
-#include <iostream>
-
-namespace blender::io::usd {
-
-USDInstanceReader::USDInstanceReader(const pxr::UsdPrim &prim,
- const USDImportParams &import_params,
- const ImportSettings &settings)
- : USDXformReader(prim, import_params, settings)
-{
-}
-
-bool USDInstanceReader::valid() const
-{
- return prim_.IsValid() && prim_.IsInstance();
-}
-
-void USDInstanceReader::create_object(Main *bmain, const double /* motionSampleTime */)
-{
- this->object_ = BKE_object_add_only_object(bmain, OB_EMPTY, name_.c_str());
- this->object_->data = nullptr;
- this->object_->transflag |= OB_DUPLICOLLECTION;
-}
-
-void USDInstanceReader::set_instance_collection(Collection *coll)
-{
- if (this->object_) {
- this->object_->instance_collection = coll;
- }
-}
-
-pxr::SdfPath USDInstanceReader::proto_path() const
-{
- if (pxr::UsdPrim master = prim_.GetMaster()) {
- return master.GetPath();
- }
-
- return pxr::SdfPath();
-}
-
-} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_instance.h b/source/blender/io/usd/intern/usd_reader_instance.h
deleted file mode 100644
index efc1c69a7dd..00000000000
--- a/source/blender/io/usd/intern/usd_reader_instance.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2021 Blender Foundation.
- * All rights reserved.
- */
-#pragma once
-
-#include "usd_reader_xform.h"
-
-#include <pxr/usd/usdGeom/xform.h>
-
-struct Collection;
-
-namespace blender::io::usd {
-
-/* Wraps the UsdGeomXform schema. Creates a Blender Empty object. */
-
-class USDInstanceReader : public USDXformReader {
-
- public:
- USDInstanceReader(const pxr::UsdPrim &prim,
- const USDImportParams &import_params,
- const ImportSettings &settings);
-
- bool valid() const override;
-
- void create_object(Main *bmain, double motionSampleTime) override;
-
- void set_instance_collection(Collection *coll);
-
- pxr::SdfPath proto_path() const;
-};
-
-} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
index 233b3d9da4d..8c4cc18a9af 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.cc
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -20,7 +20,6 @@
#include "usd_reader_stage.h"
#include "usd_reader_camera.h"
#include "usd_reader_curve.h"
-#include "usd_reader_instance.h"
#include "usd_reader_light.h"
#include "usd_reader_mesh.h"
#include "usd_reader_nurbs.h"
@@ -34,6 +33,7 @@
#include <pxr/usd/usdGeom/mesh.h>
#include <pxr/usd/usdGeom/nurbsCurves.h>
#include <pxr/usd/usdGeom/scope.h>
+#include <pxr/usd/usdGeom/xform.h>
#include <pxr/usd/usdLux/light.h>
#include <iostream>
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 22408687daf..30ca9540735 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -94,11 +94,17 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
-typedef struct ImageTile_Runtime {
+typedef struct ImageTile_RuntimeTextureSlot {
int tilearray_layer;
int _pad;
int tilearray_offset[2];
int tilearray_size[2];
+} ImageTile_RuntimeTextureSlot;
+
+typedef struct ImageTile_Runtime {
+ /* Data per `eImageTextureResolution`.
+ * Should match `IMA_TEXTURE_RESOLUTION_LEN` */
+ ImageTile_RuntimeTextureSlot slots[2];
} ImageTile_Runtime;
typedef struct ImageTile {
@@ -132,6 +138,15 @@ typedef enum eGPUTextureTarget {
TEXTARGET_COUNT,
} eGPUTextureTarget;
+/* Resolution variations that can be cached for an image. */
+typedef enum eImageTextureResolution {
+ IMA_TEXTURE_RESOLUTION_FULL = 0,
+ IMA_TEXTURE_RESOLUTION_LIMITED,
+
+ /* Not an option, but holds the number of options defined for this struct. */
+ IMA_TEXTURE_RESOLUTION_LEN
+} eImageTextureResolution;
+
typedef struct Image {
ID id;
@@ -140,8 +155,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
- struct GPUTexture *gputexture[3][2];
+ /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes, 2 = IMA_TEXTURE_RESOLUTION_LEN. */
+ struct GPUTexture *gputexture[3][2][2];
/* sources from: */
ListBase anims;
@@ -233,12 +248,15 @@ enum {
IMA_GPU_PARTIAL_REFRESH = (1 << 1),
/** All mipmap levels in OpenGL texture set? */
IMA_GPU_MIPMAP_COMPLETE = (1 << 2),
- /** Current texture resolution won't be limited by the GL Texture Limit user preference. */
- IMA_GPU_MAX_RESOLUTION = (1 << 3),
+ /* Reuse the max resolution textures as they fit in the limited scale. */
+ IMA_GPU_REUSE_MAX_RESOLUTION = (1 << 3),
+ /* Has any limited scale textures been allocated.
+ * Adds additional checks to reuse max resolution images when they fit inside limited scale. */
+ IMA_GPU_HAS_LIMITED_SCALE_TEXTURES = (1 << 4),
};
/* Image.source, where the image comes from */
-enum {
+typedef enum eImageSource {
/* IMA_SRC_CHECK = 0, */ /* UNUSED */
IMA_SRC_FILE = 1,
IMA_SRC_SEQUENCE = 2,
@@ -246,10 +264,10 @@ enum {
IMA_SRC_GENERATED = 4,
IMA_SRC_VIEWER = 5,
IMA_SRC_TILED = 6,
-};
+} eImageSource;
/* Image.type, how to handle or generate the image */
-enum {
+typedef enum eImageType {
IMA_TYPE_IMAGE = 0,
IMA_TYPE_MULTILAYER = 1,
/* generated */
@@ -257,7 +275,7 @@ enum {
/* viewers */
IMA_TYPE_R_RESULT = 4,
IMA_TYPE_COMPOSITE = 5,
-};
+} eImageType;
/* Image.gen_type */
enum {
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1cb561ddd9f..7160d2c3751 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -646,7 +646,8 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
- char _pad[5];
+ char use_geometry_nodes_fields;
+ char _pad[4];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index e44ddb07d53..4a013dc9bd7 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -404,7 +404,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index aa9fb410a14..b294e93310c 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -10300,7 +10300,7 @@ static void def_geo_attribute_capture(StructRNA *srna)
prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
- RNA_def_property_ui_text(prop, "Domain", "");
+ RNA_def_property_ui_text(prop, "Domain", "Which domain to store the data in");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index fe1b0757690..0a328c3b068 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6300,6 +6300,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
RNA_def_property_ui_text(
prop, "Override Templates", "Enable library override template in the python API");
+
+ prop = RNA_def_property(srna, "use_geometry_nodes_fields", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_geometry_nodes_fields", 1);
+ RNA_def_property_ui_text(prop, "Geometry Nodes Fields", "Enable field nodes in geometry nodes");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 11c8f0c0767..6f40687540c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -169,7 +169,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
const float length = input_splines[i]->length();
- const int count = std::max(int(length / *mode_param.length), 1);
+ const int count = std::max(int(length / *mode_param.length) + 1, 1);
output_splines[i] = resample_spline(*input_splines[i], count);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 74f43fc0cec..74740ba244f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -101,7 +101,7 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
int offset = 0;
for (const int i : IndexRange(size)) {
offsets[i] = offset;
- offset += splines[i]->length() / resolution;
+ offset += splines[i]->length() / resolution + 1;
}
offsets.last() = offset;
return offsets;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index e1e14eb367d..b8f126ef1db 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -71,7 +71,7 @@ static GVArrayPtr mesh_vertex_normals(const Mesh &mesh,
}
/* If the normals are dirty, they must be recalculated for the output of this node's field
- * source. Ideally vertex normals could be calculated lazily on a const mesh. But that's not
+ * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
* possible at the moment, so we take ownership of the results. Sadly we must also create a copy
* of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
* calculation of normals on meshes.
@@ -136,8 +136,8 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c
GVArrayPtr face_normals = mesh_face_normals(
mesh, verts, polys, loops, IndexRange(polys.size()));
- /* In this case using the mesh component's generic domain interpolation is fine,
- * since the face normal is just copied to every corner. */
+ /* In this case using the mesh component's generic domain interpolation is fine, the data
+ * will still be normalized, since the face normal is just copied to every corner. */
GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain(
std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
return scope.add_value(std::move(loop_normals), __func__).get();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 9f67638de7e..72e9e8f5c29 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -38,7 +38,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "instance_type", 0, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) {
uiItemR(layout, ptr, "use_whole_collection", 0, nullptr, ICON_NONE);
}
@@ -121,6 +121,7 @@ static Vector<InstanceReference> get_instance_references__collection(GeoNodeExec
static Vector<InstanceReference> get_instance_references__geometry(GeoNodeExecParams &params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instance Geometry");
+ geometry_set.ensure_owns_direct_data();
return {std::move(geometry_set)};
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index 48778532789..d187bf0fa71 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -17,8 +17,6 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "FN_multi_function_builder.hh"
-
#include "node_geometry_util.hh"
namespace blender::nodes {
@@ -28,7 +26,6 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::String>("Translation");
b.add_input<decl::Vector>("Translation", "Translation_001").subtype(PROP_TRANSLATION);
- b.add_input<decl::Bool>("Selection").default_value(true);
b.add_output<decl::Geometry>("Geometry");
}
@@ -39,7 +36,7 @@ static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void execute_on_component_legacy(GeoNodeExecParams params, GeometryComponent &component)
+static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
OutputAttribute_Typed<float3> position_attribute =
component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -56,87 +53,20 @@ static void execute_on_component_legacy(GeoNodeExecParams params, GeometryCompon
position_attribute.save();
}
-class SpanFieldInput final : public fn::FieldInput {
- GSpan span_;
-
- public:
- SpanFieldInput(GSpan span) : FieldInput(CPPType::get<float3>(), "Span"), span_(span)
- {
- }
- const GVArray *get_varray_for_context(const fn::FieldContext &UNUSED(context),
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
- {
- return &scope.construct<fn::GVArray_For_GSpan>(__func__, span_);
- }
-};
-
-static void execute_on_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<float3> &translation_field)
-{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
-
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- MutableSpan<float3> position_span = positions.as_span();
- fn::Field<float3> position_field{std::make_shared<SpanFieldInput>(position_span.as_span())};
-
- /* Add an add operation field on top of the provided translation field, which can be evaluated
- * directly into the position virtual array. That way, any optimizations can be done more
- * generally for the whole evaluation system. In the general case it may not work to share the
- * same span for the input and output of an evaluation, but in this case there there is only one
- * output, so it is fine. */
- static const fn::CustomMF_SI_SI_SO<float3, float3, float3> add_fn = {
- "Add", [](float3 a, float3 b) { return a + b; }};
- std::shared_ptr<fn::FieldOperation> add_operation = std::make_shared<fn::FieldOperation>(
- fn::FieldOperation(add_fn, {position_field, translation_field}));
-
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add_with_destination({add_operation}, position_span);
- position_evaluator.evaluate();
-
- positions.save();
-}
-
static void geo_node_point_translate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set = geometry_set_realize_instances(geometry_set);
- const NodeGeometryPointTranslate &storage =
- *(const NodeGeometryPointTranslate *)params.node().storage;
-
- static const Array<GeometryComponentType> types{
- GEO_COMPONENT_TYPE_MESH,
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- GEO_COMPONENT_TYPE_CURVE,
- };
-
- /* TODO: Remove legacy string input and add versioning. */
- if (storage.input_type == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) {
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- execute_on_component_legacy(params, geometry_set.get_component_for_write(type));
- }
- }
- params.error_message_add(NodeWarningType::Info, "Selection not supported in legacy mode");
+ if (geometry_set.has<MeshComponent>()) {
+ execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
}
- else {
- Field<bool> selection = params.extract_input<Field<bool>>("Selection");
- Field<float3> translation = params.extract_input<Field<float3>>("Translation_001");
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- execute_on_component(geometry_set.get_component_for_write(type), selection, translation);
- }
- }
+ if (geometry_set.has<CurveComponent>()) {
+ execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
}
params.set_output("Geometry", std::move(geometry_set));
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index 418fed146fb..ba9a1870b0c 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -274,7 +274,7 @@ bNodeSocket &build_id_socket(bNodeTree &ntree,
StringRefNull identifier)
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, data.idname, name.c_str(), identifier.c_str());
+ &ntree, &node, in_out, data.idname, identifier.c_str(), name.c_str());
if (data.hide_label) {
socket.flag |= SOCK_HIDE_LABEL;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index df051328990..81dcc5ccea0 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -552,37 +552,38 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
const View3D *v3d = (View3D *)space_data;
const View3DShading *shading = &v3d->shading;
- TEST_PTR_DATA_TYPE("space_data", RNA_View3DOverlay, ptr, v3d);
- TEST_PTR_DATA_TYPE("space_data", RNA_View3DShading, ptr, shading);
+ TEST_PTR_DATA_TYPE("space_data.overlay", RNA_View3DOverlay, ptr, v3d);
+ TEST_PTR_DATA_TYPE("space_data.shading", RNA_View3DShading, ptr, shading);
break;
}
case SPACE_GRAPH: {
const SpaceGraph *sipo = (SpaceGraph *)space_data;
const bDopeSheet *ads = sipo->ads;
- TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
break;
}
case SPACE_FILE: {
const SpaceFile *sfile = (SpaceFile *)space_data;
const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
- TEST_PTR_DATA_TYPE("space_data", RNA_FileSelectParams, ptr, params);
+ TEST_PTR_DATA_TYPE("space_data.params", RNA_FileSelectParams, ptr, params);
break;
}
case SPACE_IMAGE: {
const SpaceImage *sima = (SpaceImage *)space_data;
- TEST_PTR_DATA_TYPE("space_data", RNA_SpaceUVEditor, ptr, sima);
+ TEST_PTR_DATA_TYPE("space_data.overlay", RNA_SpaceImageOverlay, ptr, sima);
+ TEST_PTR_DATA_TYPE("space_data.uv_editor", RNA_SpaceUVEditor, ptr, sima);
break;
}
case SPACE_NLA: {
const SpaceNla *snla = (SpaceNla *)space_data;
const bDopeSheet *ads = snla->ads;
- TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
break;
}
case SPACE_ACTION: {
const SpaceAction *sact = (SpaceAction *)space_data;
const bDopeSheet *ads = &sact->ads;
- TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
break;
}
}