From a84f1c02d251a9ce6267030a46e02ed2d3ce22e1 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 25 Oct 2021 08:02:08 -0300 Subject: Assets: Snapping with visual feedback while dragging The drag and drop feature of objects in 3D View has been modified to include: - Snap the object being dragged. - Visual feedback through a box and the placement tool grid. Maniphest Tasks: T90198 Differential Revision: https://developer.blender.org/D12912 --- source/blender/blenkernel/BKE_asset.h | 17 +++++ source/blender/blenkernel/BKE_idtype.h | 5 ++ source/blender/blenkernel/BKE_main.h | 4 +- source/blender/blenkernel/intern/asset.cc | 20 ++++++ source/blender/blenkernel/intern/object.c | 37 ++++++++++ source/blender/blenloader/intern/readfile.c | 3 + source/blender/editors/asset/ED_asset_mark_clear.h | 3 + .../editors/asset/intern/asset_mark_clear.cc | 19 +++++ source/blender/editors/include/ED_view3d.h | 4 +- source/blender/editors/include/UI_interface.h | 2 + source/blender/editors/interface/interface.c | 3 +- .../interface/interface_template_asset_view.cc | 1 + source/blender/editors/object/object_add.c | 28 ++++++-- source/blender/editors/space_file/file_draw.c | 2 + source/blender/editors/space_view3d/space_view3d.c | 84 ++++++++++++++++++++-- .../editors/space_view3d/view3d_cursor_snap.c | 61 +++++++++------- source/blender/gpu/GPU_immediate_util.h | 4 ++ source/blender/gpu/intern/gpu_immediate_util.c | 27 +++++++ source/blender/makesdna/DNA_asset_types.h | 3 + source/blender/windowmanager/WM_api.h | 2 + source/blender/windowmanager/WM_types.h | 1 + source/blender/windowmanager/intern/wm_dragdrop.c | 25 ++++++- source/blender/windowmanager/intern/wm_files.c | 2 + 23 files changed, 314 insertions(+), 43 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h index 42eea41b7a7..722d142b56c 100644 --- a/source/blender/blenkernel/BKE_asset.h +++ b/source/blender/blenkernel/BKE_asset.h @@ -20,6 +20,7 @@ #pragma once +#include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" #include "DNA_asset_types.h" @@ -29,11 +30,23 @@ extern "C" { #endif struct AssetLibraryReference; +struct AssetMetaData; struct BlendDataReader; struct BlendWriter; struct ID; +struct IDProperty; struct PreviewImage; +typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data); + +typedef struct AssetTypeInfo { + /** + * For local assets (assets in the current .blend file), a callback to execute before the file is + * saved. + */ + PreSaveFn pre_save_fn; +} AssetTypeInfo; + struct AssetMetaData *BKE_asset_metadata_create(void); void BKE_asset_metadata_free(struct AssetMetaData **asset_data); @@ -56,6 +69,10 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data, void BKE_asset_library_reference_init_default(struct AssetLibraryReference *library_ref); +void BKE_asset_metadata_idprop_ensure(struct AssetMetaData *asset_data, struct IDProperty *prop); +struct IDProperty *BKE_asset_metadata_idprop_find(const struct AssetMetaData *asset_data, + const char *name) ATTR_WARN_UNUSED_RESULT; + struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data, const struct ID *owner_id); diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h index cd656d94fce..d33c24f2c75 100644 --- a/source/blender/blenkernel/BKE_idtype.h +++ b/source/blender/blenkernel/BKE_idtype.h @@ -228,6 +228,11 @@ typedef struct IDTypeInfo { * \note Currently needed for some update operation on point caches. */ IDTypeLibOverrideApplyPost lib_override_apply_post; + + /** + * Callbacks for assets, based on the type of asset. + */ + struct AssetTypeInfo *asset_type_info; } IDTypeInfo; /* ********** Declaration of each IDTypeInfo. ********** */ diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 68b1b55f47f..9ded97e0003 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -244,9 +244,9 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe #define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id) \ { \ - ID *_id_next = (_lb)->first; \ + ID *_id_next = (ID *)(_lb)->first; \ for ((_id) = _id_next; (_id) != NULL; (_id) = _id_next) { \ - _id_next = (_id)->next; + _id_next = (ID *)(_id)->next; #define FOREACH_MAIN_LISTBASE_ID_END \ } \ diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index dfe568729db..7bea089b9bf 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -141,6 +141,25 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data, trimmed_id.copy(asset_data->catalog_simple_name, max_simple_name_length); } +void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop) +{ + if (!asset_data->properties) { + IDPropertyTemplate val = {0}; + asset_data->properties = IDP_New(IDP_GROUP, &val, "AssetMetaData.properties"); + } + /* Important: The property may already exist. For now just allow always allow a newly allocated + * property, and replace the existing one as a way of updating. */ + IDP_ReplaceInGroup(asset_data->properties, prop); +} + +IDProperty *BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name) +{ + if (!asset_data->properties) { + return nullptr; + } + return IDP_GetPropertyFromGroup(asset_data->properties, name); +} + /* Queries -------------------------------------------- */ PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data), @@ -173,6 +192,7 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data) void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data) { /* asset_data itself has been read already. */ + asset_data->local_type_info = nullptr; if (asset_data->properties) { BLO_read_data_address(reader, &asset_data->properties); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e85c6b4c7c5..45dfb9af074 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -82,6 +82,7 @@ #include "BKE_anim_visualization.h" #include "BKE_animsys.h" #include "BKE_armature.h" +#include "BKE_asset.h" #include "BKE_camera.h" #include "BKE_collection.h" #include "BKE_constraint.h" @@ -1190,6 +1191,40 @@ static void object_lib_override_apply_post(ID *id_dst, ID *id_src) BLI_freelistN(&pidlist_src); } +static IDProperty *object_asset_dimensions_property(Object *ob) +{ + float dimensions[3]; + BKE_object_dimensions_get(ob, dimensions); + if (is_zero_v3(dimensions)) { + return NULL; + } + + IDPropertyTemplate idprop = {0}; + idprop.array.len = ARRAY_SIZE(dimensions); + idprop.array.type = IDP_FLOAT; + + IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "dimensions"); + memcpy(IDP_Array(property), dimensions, sizeof(dimensions)); + + return property; +} + +static void object_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data) +{ + Object *ob = asset_ptr; + BLI_assert(GS(ob->id.name) == ID_OB); + + /* Update dimensions hint for the asset. */ + IDProperty *dimensions_prop = object_asset_dimensions_property(ob); + if (dimensions_prop) { + BKE_asset_metadata_idprop_ensure(asset_data, dimensions_prop); + } +} + +AssetTypeInfo AssetType_OB = { + .pre_save_fn = object_asset_pre_save, +}; + IDTypeInfo IDType_ID_OB = { .id_code = ID_OB, .id_filter = FILTER_ID_OB, @@ -1216,6 +1251,8 @@ IDTypeInfo IDType_ID_OB = { .blend_read_undo_preserve = NULL, .lib_override_apply_post = object_lib_override_apply_post, + + .asset_type_info = &AssetType_OB, }; void BKE_object_workob_clear(Object *workob) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 0b69395b4f8..600abcca818 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2211,6 +2211,9 @@ static void direct_link_id_common( if (id->asset_data) { BLO_read_data_address(reader, &id->asset_data); BKE_asset_metadata_read(reader, id->asset_data); + /* Restore runtime asset type info. */ + const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); + id->asset_data->local_type_info = id_type->asset_type_info; } /* Link direct data of ID properties. */ diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h index bab1d1bf8a5..8e6a8e11d69 100644 --- a/source/blender/editors/asset/ED_asset_mark_clear.h +++ b/source/blender/editors/asset/ED_asset_mark_clear.h @@ -26,6 +26,7 @@ extern "C" { struct ID; struct bContext; +struct Main; /** * Mark the datablock as asset. @@ -52,6 +53,8 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id); * \return whether the asset metadata was actually removed; false when the ID was not an asset. */ bool ED_asset_clear_id(struct ID *id); +void ED_assets_pre_save(struct Main *bmain); + bool ED_asset_can_mark_single_from_context(const struct bContext *C); #ifdef __cplusplus diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc index 4be7376a1c3..eb254dcd28b 100644 --- a/source/blender/editors/asset/intern/asset_mark_clear.cc +++ b/source/blender/editors/asset/intern/asset_mark_clear.cc @@ -25,7 +25,9 @@ #include "BKE_asset.h" #include "BKE_context.h" +#include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_main.h" #include "BLO_readfile.h" @@ -52,7 +54,9 @@ bool ED_asset_mark_id(ID *id) id_fake_user_set(id); + const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id); id->asset_data = BKE_asset_metadata_create(); + id->asset_data->local_type_info = id_type_info->asset_type_info; /* Important for asset storage to update properly! */ ED_assetlist_storage_tag_main_data_dirty(); @@ -79,6 +83,21 @@ bool ED_asset_clear_id(ID *id) return true; } +void ED_assets_pre_save(struct Main *bmain) +{ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (!id->asset_data || !id->asset_data->local_type_info) { + continue; + } + + if (id->asset_data->local_type_info->pre_save_fn) { + id->asset_data->local_type_info->pre_save_fn(id, id->asset_data); + } + } + FOREACH_MAIN_ID_END; +} + bool ED_asset_can_mark_single_from_context(const bContext *C) { /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 67c470a005f..a0c733b2ebf 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -276,12 +276,15 @@ typedef struct V3DSnapCursorState { eV3DPlaceOrient plane_orient; uchar color_line[4]; uchar color_point[4]; + uchar color_box[4]; float *prevpoint; + float box_dimensions[3]; short snap_elem_force; /* If zero, use scene settings. */ short plane_axis; bool use_plane_axis_auto; bool draw_point; bool draw_plane; + bool draw_box; } V3DSnapCursorState; void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state); @@ -293,7 +296,6 @@ V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state, const struct bContext *C, const int x, const int y); - struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene); void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, const float loc_prev[3], diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 4cd921bc61e..1ac20a5d070 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -37,6 +37,7 @@ extern "C" { struct ARegion; struct AssetFilterSettings; struct AssetHandle; +struct AssetMetaData; struct AutoComplete; struct EnumPropertyItem; struct FileDirEntry; @@ -785,6 +786,7 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id); void UI_but_drag_set_asset(uiBut *but, const struct AssetHandle *asset, const char *path, + struct AssetMetaData *metadata, int import_type, /* eFileAssetImportType */ int icon, struct ImBuf *imb, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 5068969946a..62c84ed38ff 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -6231,12 +6231,13 @@ void UI_but_drag_set_id(uiBut *but, ID *id) void UI_but_drag_set_asset(uiBut *but, const AssetHandle *asset, const char *path, + struct AssetMetaData *metadata, int import_type, int icon, struct ImBuf *imb, float scale) { - wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, path, import_type); + wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type); /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the * #wmDropBox. diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index f27b37a27de..d3ce7ebc3db 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -70,6 +70,7 @@ static void asset_view_item_but_drag_set(uiBut *but, UI_but_drag_set_asset(but, asset_handle, BLI_strdup(blend_path), + ED_asset_handle_get_metadata(asset_handle), FILE_ASSET_IMPORT_APPEND, ED_asset_handle_get_preview_icon_id(asset_handle), imbuf, diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 114f540b614..629f40e0ae9 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -3533,12 +3533,6 @@ static int object_add_named_exec(bContext *C, wmOperator *op) basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT; - int mval[2]; - if (object_add_drop_xy_get(C, op, &mval)) { - ED_object_location_from_view(C, basen->object->loc); - ED_view3d_cursor3d_position(C, mval, false, basen->object->loc); - } - /* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or * BKE_view_layer_base_deselect_all(). */ ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT); @@ -3556,13 +3550,29 @@ static int object_add_named_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); ED_outliner_select_sync_from_object_tag(C); + PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + if (RNA_property_is_set(op->ptr, prop_matrix)) { + Object *ob_add = basen->object; + RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->obmat[0][0]); + BKE_object_apply_mat4(ob_add, ob_add->obmat, true, true); + + DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM); + } + else { + int mval[2]; + if (object_add_drop_xy_get(C, op, &mval)) { + ED_object_location_from_view(C, basen->object->loc); + ED_view3d_cursor3d_position(C, mval, false, basen->object->loc); + } + } + return OPERATOR_FINISHED; } void OBJECT_OT_add_named(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Named Object"; + ot->name = "Add Object"; ot->description = "Add named object"; ot->idname = "OBJECT_OT_add_named"; @@ -3594,6 +3604,10 @@ void OBJECT_OT_add_named(wmOperatorType *ot) RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add"); + prop = RNA_def_float_matrix( + ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + object_add_drop_xy_props(ot); } diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 24b24eb81dd..5c6b753d4a5 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -190,6 +190,7 @@ static void file_draw_icon(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), + file->asset_data, asset_params->import_type, icon, preview_image, @@ -515,6 +516,7 @@ static void file_draw_preview(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), + file->asset_data, asset_params->import_type, icon, imb, diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index eb30d0987ab..eaf90aabe8c 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -40,6 +40,7 @@ #include "BLT_translation.h" +#include "BKE_asset.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_global.h" @@ -515,6 +516,45 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C, return WM_drag_is_ID_type(drag, id_type); } +static void view3d_ob_drop_draw_activate(struct wmDropBox *drop, wmDrag *drag) +{ + V3DSnapCursorState *state = drop->draw_data; + if (state) { + return; + } + state = drop->draw_data = ED_view3d_cursor_snap_active(); + state->draw_point = true; + state->draw_plane = true; + + float dimensions[3] = {0.0f}; + if (drag->type == WM_DRAG_ID) { + Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); + BKE_object_dimensions_get(ob, dimensions); + } + else { + struct AssetMetaData *meta_data = WM_drag_get_asset_meta_data(drag, ID_OB); + IDProperty *dimensions_prop = BKE_asset_metadata_idprop_find(meta_data, "dimensions"); + if (dimensions_prop) { + copy_v3_v3(dimensions, IDP_Array(dimensions_prop)); + } + } + + if (!is_zero_v3(dimensions)) { + mul_v3_v3fl(state->box_dimensions, dimensions, 0.5f); + UI_GetThemeColor4ubv(TH_GIZMO_PRIMARY, state->color_box); + state->draw_box = true; + } +} + +static void view3d_ob_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSED(drag)) +{ + V3DSnapCursorState *state = drop->draw_data; + if (state) { + ED_view3d_cursor_snap_deactive(state); + drop->draw_data = NULL; + } +} + static bool view3d_ob_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { return view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB); @@ -639,6 +679,31 @@ static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) /* Don't duplicate ID's which were just imported. Only do that for existing, local IDs. */ const bool is_imported_id = drag->type == WM_DRAG_ASSET; RNA_boolean_set(drop->ptr, "duplicate", !is_imported_id); + + V3DSnapCursorState *snap_state = drop->draw_data; + if (snap_state) { + Object *ob = (Object *)id; + float obmat_final[4][4]; + + V3DSnapCursorData *snap_data; + snap_data = ED_view3d_cursor_snap_data_get(snap_state, NULL, 0, 0); + copy_m4_m3(obmat_final, snap_data->plane_omat); + copy_v3_v3(obmat_final[3], snap_data->loc); + + float scale[3]; + mat4_to_size(scale, ob->obmat); + rescale_m4(obmat_final, scale); + + BoundBox *bb = BKE_object_boundbox_get(ob); + if (bb) { + float offset[3]; + BKE_boundbox_calc_center_aabb(bb, offset); + offset[2] = bb->vec[0][2]; + mul_mat3_m4_v3(obmat_final, offset); + sub_v3_v3(obmat_final[3], offset); + } + RNA_float_set_array(drop->ptr, "matrix", &obmat_final[0][0]); + } } static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) @@ -703,12 +768,19 @@ static void view3d_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, - "OBJECT_OT_add_named", - view3d_ob_drop_poll, - view3d_ob_drop_copy, - WM_drag_free_imported_drag_ID, - NULL); + struct wmDropBox *drop; + drop = WM_dropbox_add(lb, + "OBJECT_OT_add_named", + view3d_ob_drop_poll, + view3d_ob_drop_copy, + WM_drag_free_imported_drag_ID, + NULL); + + drop->draw = WM_drag_draw_item_name_fn; + drop->draw_activate = view3d_ob_drop_draw_activate; + drop->draw_deactivate = view3d_ob_drop_draw_deactivate; + drop->opcontext = WM_OP_EXEC_DEFAULT; /* Not really needed. */ + WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 1cb650910ce..5eb9ec3625c 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -58,7 +58,6 @@ typedef struct SnapStateIntern { V3DSnapCursorState snap_state; - float prevpoint_stack[3]; int state_active_prev; bool is_active; } SnapStateIntern; @@ -75,6 +74,8 @@ typedef struct SnapCursorDataIntern { const Scene *scene; short snap_elem_hidden; + float prevpoint_stack[3]; + /* Copy of the parameters of the last event state in order to detect updates. */ struct { int x; @@ -94,17 +95,6 @@ typedef struct SnapCursorDataIntern { bool is_initiated; } SnapCursorDataIntern; -static void UNUSED_FUNCTION(v3d_cursor_snap_state_init)(V3DSnapCursorState *state) -{ - state->prevpoint = NULL; - state->snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT); - state->plane_axis = 2; - rgba_uchar_args_set(state->color_point, 255, 255, 255, 255); - rgba_uchar_args_set(state->color_line, 255, 255, 255, 128); - state->draw_point = true; - state->draw_plane = false; -} static SnapCursorDataIntern g_data_intern = { .state_default = {.prevpoint = NULL, .snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | @@ -113,8 +103,9 @@ static SnapCursorDataIntern g_data_intern = { .plane_axis = 2, .color_point = {255, 255, 255, 255}, .color_line = {255, 255, 255, 128}, - .draw_point = true, - .draw_plane = false}}; + .color_box = {255, 255, 255, 128}, + .box_dimensions = {1.0f, 1.0f, 1.0f}, + .draw_point = true}}; /** * Calculate a 3x3 orientation matrix from the surface under the cursor. @@ -373,6 +364,24 @@ static void v3d_cursor_plane_draw(const RegionView3D *rv3d, } } +static void cursor_box_draw(const float dimensions[3], uchar color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPU_blend(GPU_BLEND_ALPHA); + GPU_line_smooth(true); + GPU_line_width(1.0f); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4ubv(color); + imm_draw_cube_corners_3d(pos_id, (float[3]){0.0f, 0.0f, dimensions[2]}, dimensions, 0.15f); + immUnbindProgram(); + + GPU_line_smooth(false); + GPU_blend(GPU_BLEND_NONE); +} + void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d, const float loc_prev[3], const float loc_curr[3], @@ -601,7 +610,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, ushort snap_elements = v3d_cursor_snap_elements(state, scene); data_intern->snap_elem_hidden = 0; - const bool draw_plane = state->draw_plane; + const bool draw_plane = state->draw_plane || state->draw_box; if (draw_plane && !(snap_elements & SCE_SNAP_MODE_FACE)) { data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE; snap_elements |= SCE_SNAP_MODE_FACE; @@ -674,6 +683,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, } if (draw_plane) { + RegionView3D *rv3d = region->regiondata; bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE); if (orient_surface) { copy_m3_m4(omat, obmat); @@ -686,7 +696,6 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, ED_transform_calc_orientation_from_type_ex( scene, view_layer, v3d, region->regiondata, ob, ob, orient_index, pivot_point, omat); - RegionView3D *rv3d = region->regiondata; if (state->use_plane_axis_auto) { mat3_align_axis_to_v3(omat, state->plane_axis, rv3d->viewinv[2]); } @@ -699,6 +708,9 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, orthogonalize_m3(omat, state->plane_axis); if (orient_surface) { + if (dot_v3v3(rv3d->viewinv[2], face_nor) < 0.0f) { + negate_v3(face_nor); + } v3d_cursor_poject_surface_normal(face_nor, obmat, omat); } } @@ -791,7 +803,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust v3d_cursor_snap_update(state, C, wm, depsgraph, scene, region, v3d, x, y); } - const bool draw_plane = state->draw_plane; + const bool draw_plane = state->draw_plane || state->draw_box; if (!snap_data->snap_elem && !draw_plane) { return; } @@ -802,8 +814,6 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust GPU_matrix_projection_set(rv3d->winmat); GPU_matrix_set(rv3d->viewmat); - GPU_blend(GPU_BLEND_ALPHA); - float matrix[4][4]; if (draw_plane) { copy_m4_m3(matrix, snap_data->plane_omat); @@ -812,7 +822,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix); } - if (snap_data->snap_elem && state->draw_point) { + if (snap_data->snap_elem && (state->draw_point || state->draw_box)) { const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ? state->prevpoint : NULL; @@ -829,7 +839,10 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust snap_data->snap_elem); } - GPU_blend(GPU_BLEND_NONE); + if (state->draw_box) { + GPU_matrix_mul(matrix); + cursor_box_draw(state->box_dimensions, state->color_box); + } /* Restore matrix. */ wmWindowViewport(CTX_wm_window(C)); @@ -942,10 +955,10 @@ void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state) void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3]) { - SnapStateIntern *state_intern = (SnapStateIntern *)state; + SnapCursorDataIntern *data_intern = &g_data_intern; if (prev_point) { - copy_v3_v3(state_intern->prevpoint_stack, prev_point); - state->prevpoint = state_intern->prevpoint_stack; + copy_v3_v3(data_intern->prevpoint_stack, prev_point); + state->prevpoint = data_intern->prevpoint_stack; } else { state->prevpoint = NULL; diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 3ea809d59a7..793348ad8d2 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -80,6 +80,10 @@ void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2); void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]); void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]); +void imm_draw_cube_corners_3d(uint pos, + const float co[3], + const float aspect[3], + const float factor); void imm_draw_cylinder_fill_normal_3d( uint pos, uint nor, float base, float top, float height, int slices, int stacks); diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index d18dc862ce7..d848ea09a2a 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -428,6 +428,33 @@ void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]) immEnd(); } +void imm_draw_cube_corners_3d(uint pos, + const float co[3], + const float aspect[3], + const float factor) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + } + + immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 4); + for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) { + float vec[3], co[3]; + sub_v3_v3v3(vec, coords[cube_line_index[i][1]], coords[cube_line_index[i][0]]); + mul_v3_fl(vec, factor); + + immVertex3fv(pos, coords[cube_line_index[i][0]]); + add_v3_v3v3(co, coords[cube_line_index[i][0]], vec); + immVertex3fv(pos, co); + sub_v3_v3v3(co, coords[cube_line_index[i][1]], vec); + immVertex3fv(pos, co); + immVertex3fv(pos, coords[cube_line_index[i][1]]); + } + immEnd(); +} + /** * Draw a cylinder. Replacement for gluCylinder. * _warning_ : Slow, better use it only if you no other choices. diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index 60de254fec7..bd604b90b5a 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -56,6 +56,9 @@ typedef struct AssetFilterSettings { * more than that from the file. So pointers to other IDs or ID data are strictly forbidden. */ typedef struct AssetMetaData { + /** Runtime type, to reference event callbacks. Only valid for local assets. */ + struct AssetTypeInfo *local_type_info; + /** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */ struct IDProperty *properties; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index c7087b28783..2988aacc4d3 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -757,9 +757,11 @@ struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short id bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode); wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset, + struct AssetMetaData *metadata, const char *path, int import_type); struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode); +struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode); struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode); void WM_drag_free_imported_drag_ID(struct Main *bmain, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index bbfc9d53e44..2813047f0e4 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -989,6 +989,7 @@ typedef struct wmDragAsset { /* Always freed. */ const char *path; int id_type; + struct AssetMetaData *metadata; int import_type; /* eFileAssetImportType */ /* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index bad58c32cdb..f78bd528c5e 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -40,6 +40,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -405,11 +406,15 @@ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode) /** * \note: Does not store \a asset in any way, so it's fine to pass a temporary. */ -wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type) +wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, + AssetMetaData *metadata, + const char *path, + int import_type) { wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset"); BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name)); + asset_drag->metadata = metadata; asset_drag->path = path; asset_drag->id_type = ED_asset_handle_get_id_type(asset); asset_drag->import_type = import_type; @@ -433,6 +438,21 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode) return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL; } +struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode) +{ + wmDragAsset *drag_asset = WM_drag_get_asset_data(drag, idcode); + if (drag_asset) { + return drag_asset->metadata; + } + + ID *local_id = WM_drag_get_local_ID(drag, idcode); + if (local_id) { + return local_id->asset_data; + } + + return NULL; +} + static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag) { const char *name = asset_drag->name; @@ -566,11 +586,12 @@ void WM_drag_add_asset_list_item( drag_asset->asset_data.local_id = local_id; } else { + AssetMetaData *metadata = ED_asset_handle_get_metadata(asset); char asset_blend_path[FILE_MAX_LIBEXTRA]; ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path); drag_asset->is_external = true; drag_asset->asset_data.external_info = WM_drag_create_asset_data( - asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND); + asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND); } BLI_addtail(&drag->asset_items, drag_asset); } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 2525c627785..8fcc30dfed7 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1788,6 +1788,7 @@ static bool wm_file_write(bContext *C, /* Call pre-save callbacks before writing preview, * that way you can generate custom file thumbnail. */ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE); + ED_assets_pre_save(bmain); /* Enforce full override check/generation on file save. */ BKE_lib_override_library_main_operations_create(bmain, true); @@ -2105,6 +2106,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) } BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE); + ED_assets_pre_save(bmain); /* check current window and close it if temp */ if (win && WM_window_is_temp_screen(win)) { -- cgit v1.2.3