diff options
author | Jacques Lucke <jacques@blender.org> | 2021-09-09 18:45:46 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-09-09 18:45:46 +0300 |
commit | bcae5507b83ef19acf409fa80c5b8c060f58b0f3 (patch) | |
tree | abf4a2d43e8d00c7d55c94c5adec2551ae7a6fac | |
parent | 2920a569b527c3543dd393a96bca2362ee04feef (diff) | |
parent | 29704854dfd7940409edf4c9f6709f3f30a3595a (diff) |
Merge branch 'temp-geometry-nodes-fields' into parallel-multi-function
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 ¶ms, 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 ¶ms) { 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; } } |