diff options
Diffstat (limited to 'source/blender/editors/object')
-rw-r--r-- | source/blender/editors/object/object_add.c | 235 | ||||
-rw-r--r-- | source/blender/editors/object/object_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_ops.c | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_relations.c | 24 | ||||
-rw-r--r-- | source/blender/editors/object/object_utils.c | 68 |
5 files changed, 253 insertions, 76 deletions
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 114f540b614..d22ae5bc804 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1323,6 +1323,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front"); const bool use_lights = RNA_boolean_get(op->ptr, "use_lights"); const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order"); + const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset"); ushort local_view_bits; float loc[3], rot[3]; @@ -1454,6 +1455,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) if (stroke_depth_order == GP_DRAWMODE_3D) { gpd->draw_mode = GP_DRAWMODE_3D; } + md->stroke_depth_offset = stroke_depth_offset; } break; @@ -1491,9 +1493,10 @@ static void object_add_ui(bContext *UNUSED(C), wmOperator *op) uiItemR(layout, op->ptr, "use_lights", 0, NULL, ICON_NONE); uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE); bool in_front = RNA_boolean_get(op->ptr, "use_in_front"); - uiLayout *row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, !in_front); - uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, !in_front); + uiItemR(col, op->ptr, "stroke_depth_offset", 0, NULL, ICON_NONE); + uiItemR(col, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE); } } @@ -1532,9 +1535,18 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); RNA_def_boolean(ot->srna, "use_in_front", - false, - "In Front", + true, + "Show In Front", "Show line art grease pencil in front of everything"); + RNA_def_float(ot->srna, + "stroke_depth_offset", + 0.05f, + 0.0f, + FLT_MAX, + "Stroke Offset", + "Stroke offset for the line art modifier", + 0.0f, + 0.5f); RNA_def_boolean( ot->srna, "use_lights", false, "Use Lights", "Use lights for this grease pencil object"); RNA_def_enum( @@ -1543,7 +1555,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) rna_enum_gpencil_add_stroke_depth_order_items, GP_DRAWMODE_3D, "Stroke Depth Order", - "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'"); + "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front')"); } /** \} */ @@ -2133,7 +2145,7 @@ static void copy_object_set_idnew(bContext *C) Main *bmain = CTX_data_main(C); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_libblock_relink_to_newid(&ob->id); + BKE_libblock_relink_to_newid(bmain, &ob->id); } CTX_DATA_END; @@ -2366,7 +2378,7 @@ static void make_object_duplilist_real(bContext *C, Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob_dst->id); + BKE_libblock_relink_to_newid(bmain, &ob_dst->id); DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); @@ -3363,7 +3375,7 @@ Base *ED_object_add_duplicate( ob = basen->object; /* link own references to the newly duplicated data T26816. */ - BKE_libblock_relink_to_newid(&ob->id); + BKE_libblock_relink_to_newid(bmain, &ob->id); /* DAG_relations_tag_update(bmain); */ /* caller must do */ @@ -3469,19 +3481,6 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) * Use for drag & drop. * \{ */ -static Base *object_add_ensure_in_view_layer(Main *bmain, ViewLayer *view_layer, Object *ob) -{ - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (!base) { - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, ob); - base = BKE_view_layer_base_find(view_layer, ob); - } - - return base; -} - static int object_add_named_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -3489,8 +3488,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Base *basen; Object *ob; - const bool duplicate = RNA_boolean_get(op->ptr, "duplicate"); - const bool linked = duplicate && RNA_boolean_get(op->ptr, "linked"); + const bool linked = RNA_boolean_get(op->ptr, "linked"); const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag; char name[MAX_ID_NAME - 2]; @@ -3504,41 +3502,26 @@ static int object_add_named_exec(bContext *C, wmOperator *op) } /* prepare dupli */ - if (duplicate) { - basen = object_add_duplicate_internal( - bmain, - scene, - view_layer, - ob, - dupflag, - /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this - * function will only work if the object is already linked in the view layer, which is not - * the case here. So we have to do the new-ID relinking ourselves - * (#copy_object_set_idnew()). - */ - LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID); - } - else { - /* basen is actually not a new base in this case. */ - basen = object_add_ensure_in_view_layer(bmain, view_layer, ob); - } + basen = object_add_duplicate_internal( + bmain, + scene, + view_layer, + ob, + dupflag, + /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this + * function will only work if the object is already linked in the view layer, which is not + * the case here. So we have to do the new-ID relinking ourselves + * (#copy_object_set_idnew()). + */ + LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID); if (basen == NULL) { - BKE_report(op->reports, - RPT_ERROR, - duplicate ? "Object could not be duplicated" : - "Object could not be linked to the view layer"); + BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } 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,44 +3539,164 @@ 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"; /* api callbacks */ ot->invoke = object_add_drop_xy_generic_invoke; ot->exec = object_add_named_exec; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode_poll_msg; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; PropertyRNA *prop; - - prop = RNA_def_boolean( - ot->srna, - "duplicate", - true, - "Duplicate", - "Create a duplicate of the object. If not set, only ensures the object is linked into the " - "active view layer, positions and selects/activates it (deselecting others)"); - RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_boolean(ot->srna, "linked", false, "Linked", - "Duplicate object but not object data, linking to the original data (ignored if " - "'duplicate' is false)"); + "Duplicate object but not object data, linking to the original data"); 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); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Object to Mouse Operator + * \{ */ + +/** + * Alternate behavior for dropping an asset that positions the appended object(s). + */ +static int object_transform_to_mouse_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob; + + if (RNA_struct_property_is_set(op->ptr, "name")) { + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name); + } + else { + ob = OBACT(view_layer); + } + + if (ob == NULL) { + BKE_report(op->reports, RPT_ERROR, "Object not found"); + return OPERATOR_CANCELLED; + } + + /* Don't transform a linked object. There's just nothing to do here in this case, so return + * #OPERATOR_FINISHED. */ + if (ID_IS_LINKED(ob)) { + return OPERATOR_FINISHED; + } + + /* Ensure the locations are updated so snap reads the evaluated active location. */ + CTX_data_ensure_evaluated_depsgraph(C); + + PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + if (RNA_property_is_set(op->ptr, prop_matrix)) { + uint objects_len; + Object **objects = BKE_view_layer_array_selected_objects(view_layer, NULL, &objects_len, {0}); + + float matrix[4][4]; + RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); + + float mat_src_unit[4][4]; + float mat_dst_unit[4][4]; + float final_delta[4][4]; + + normalize_m4_m4(mat_src_unit, ob->obmat); + normalize_m4_m4(mat_dst_unit, matrix); + invert_m4(mat_src_unit); + mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit); + + ED_object_xform_array_m4(objects, objects_len, final_delta); + + MEM_freeN(objects); + } + else { + int mval[2]; + if (object_add_drop_xy_get(C, op, &mval)) { + float cursor[3]; + ED_object_location_from_view(C, cursor); + ED_view3d_cursor3d_position(C, mval, false, cursor); + + /* Use the active objects location since this is the ID which the user selected to drop. + * + * This transforms all selected objects, so that dropping a single object which links in + * other objects will have their relative transformation preserved. + * For example a child/parent relationship or other objects used with a boolean modifier. + * + * The caller is responsible for ensuring the selection state gives useful results. + * Link/append does this using #FILE_AUTOSELECT. */ + ED_view3d_snap_selected_to_location(C, cursor, V3D_AROUND_ACTIVE); + } + } + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_transform_to_mouse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Place Object Under Mouse"; + ot->description = "Snap selected item(s) to the mouse location"; + ot->idname = "OBJECT_OT_transform_to_mouse"; + + /* api callbacks */ + ot->invoke = object_add_drop_xy_generic_invoke; + ot->exec = object_transform_to_mouse_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + RNA_def_string(ot->srna, + "name", + NULL, + MAX_ID_NAME - 2, + "Name", + "Object name to place (when unset use the active object)"); + + 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/object/object_intern.h b/source/blender/editors/object/object_intern.h index ea9a2de090b..fe07ecef438 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -106,6 +106,7 @@ void OBJECT_OT_select_same_collection(struct wmOperatorType *ot); /* object_add.c */ void OBJECT_OT_add(struct wmOperatorType *ot); void OBJECT_OT_add_named(struct wmOperatorType *ot); +void OBJECT_OT_transform_to_mouse(struct wmOperatorType *ot); void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index b3bf2c64a91..b171da42522 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -112,6 +112,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_volume_import); WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_add_named); + WM_operatortype_append(OBJECT_OT_transform_to_mouse); WM_operatortype_append(OBJECT_OT_effector_add); WM_operatortype_append(OBJECT_OT_collection_instance_add); WM_operatortype_append(OBJECT_OT_data_instance_add); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d81143d6081..acd3f058554 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1685,18 +1685,20 @@ static bool single_data_needs_duplication(ID *id) return (id != NULL && (id->us > 1 || ID_IS_LINKED(id))); } -static void libblock_relink_collection(Collection *collection, const bool do_collection) +static void libblock_relink_collection(Main *bmain, + Collection *collection, + const bool do_collection) { if (do_collection) { - BKE_libblock_relink_to_newid(&collection->id); + BKE_libblock_relink_to_newid(bmain, &collection->id); } for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { - BKE_libblock_relink_to_newid(&cob->ob->id); + BKE_libblock_relink_to_newid(bmain, &cob->ob->id); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - libblock_relink_collection(child->collection, true); + libblock_relink_collection(bmain, child->collection, true); } } @@ -1766,10 +1768,10 @@ static void single_object_users( single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); /* Will also handle the master collection. */ - BKE_libblock_relink_to_newid(&scene->id); + BKE_libblock_relink_to_newid(bmain, &scene->id); /* Collection and object pointers in collections */ - libblock_relink_collection(scene->master_collection, false); + libblock_relink_collection(bmain, scene->master_collection, false); /* We also have to handle runtime things in UI. */ if (v3d) { @@ -2589,10 +2591,10 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) char *ED_object_ot_drop_named_material_tooltip(bContext *C, PointerRNA *properties, - const wmEvent *event) + const int mval[2]) { int mat_slot = 0; - Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot); + Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot); if (ob == NULL) { return BLI_strdup(""); } @@ -2642,8 +2644,10 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_FINISHED; } -/* used for dropbox */ -/* assigns to object under cursor, only first material slot */ +/** + * Used for drop-box. + * Assigns to object under cursor, only first material slot. + */ void OBJECT_OT_drop_named_material(wmOperatorType *ot) { /* identifiers */ diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 66390f6f165..c7dfe911ce7 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -36,6 +36,7 @@ #include "BKE_armature.h" #include "BKE_editmesh.h" #include "BKE_lattice.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "DEG_depsgraph_query.h" @@ -430,3 +431,70 @@ void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xd } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Object Array + * + * Low level object transform function, transforming objects by `matrix`. + * Simple alternative to full transform logic. + * \{ */ + +static bool object_parent_in_set(GSet *objects_set, Object *ob) +{ + for (Object *parent = ob->parent; parent; parent = parent->parent) { + if (BLI_gset_lookup(objects_set, parent)) { + return true; + } + } + return false; +} + +void ED_object_xform_array_m4(Object **objects, uint objects_len, const float matrix[4][4]) +{ + /* Filter out objects that have parents in `objects_set`. */ + { + GSet *objects_set = BLI_gset_ptr_new_ex(__func__, objects_len); + for (uint i = 0; i < objects_len; i++) { + BLI_gset_add(objects_set, objects[i]); + } + for (uint i = 0; i < objects_len;) { + if (object_parent_in_set(objects_set, objects[i])) { + objects[i] = objects[--objects_len]; + } + else { + i++; + } + } + BLI_gset_free(objects_set, NULL); + } + + /* Detect translation only matrix, prevent rotation/scale channels from being touched at all. */ + bool is_translation_only; + { + float test_m4_a[4][4], test_m4_b[4][4]; + unit_m4(test_m4_a); + copy_m4_m4(test_m4_b, matrix); + zero_v3(test_m4_b[3]); + is_translation_only = equals_m4m4(test_m4_a, test_m4_b); + } + + if (is_translation_only) { + for (uint i = 0; i < objects_len; i++) { + Object *ob = objects[i]; + add_v3_v3(ob->loc, matrix[3]); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + } + else { + for (uint i = 0; i < objects_len; i++) { + float m4[4][4]; + Object *ob = objects[i]; + BKE_object_to_mat4(ob, m4); + mul_m4_m4m4(m4, matrix, m4); + BKE_object_apply_mat4(ob, m4, true, true); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + } +} + +/** \} */ |