[Bf-blender-cvs] [eb1ede56931] master: Assets: Instancing operator option for collection asset dropping

Julian Eisel noreply at git.blender.org
Fri Apr 1 16:52:14 CEST 2022


Commit: eb1ede569316027803e8327af92029f2b9598944
Author: Julian Eisel
Date:   Fri Apr 1 16:41:52 2022 +0200
Branches: master
https://developer.blender.org/rBeb1ede569316027803e8327af92029f2b9598944

Assets: Instancing operator option for collection asset dropping

Makes it possible to toggle instancing via the "Adjust Last Operation"
panel after dropping a collection asset into the viewport.

A design task that puts this into more context is pending still, but
this is a useful option to have either way.

Differential Revision: https://developer.blender.org/D14507

Reviewed by: Bastien Montagne

===================================================================

M	source/blender/editors/object/object_add.cc
M	source/blender/editors/object/object_intern.h
M	source/blender/editors/object/object_ops.c
M	source/blender/editors/space_view3d/space_view3d.c

===================================================================

diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index f681f49df90..6a7920d4d75 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -8,6 +8,7 @@
 #include <cctype>
 #include <cstdlib>
 #include <cstring>
+#include <optional>
 
 #include "MEM_guardedalloc.h"
 
@@ -1629,66 +1630,100 @@ void OBJECT_OT_light_add(wmOperatorType *ot)
 /** \name Add Collection Instance Operator
  * \{ */
 
-static int collection_instance_add_exec(bContext *C, wmOperator *op)
-{
-  Main *bmain = CTX_data_main(C);
+struct CollectionAddInfo {
+  /* The collection that is supposed to be added, determined through operator properties. */
   Collection *collection;
+  /* The local-view bits (if any) the object should have set to become visible in current context.
+   */
   ushort local_view_bits;
+  /* The transform that should be applied to the collection, determined through operator properties
+   * if set (e.g. to place the collection under the cursor), otherwise through context (e.g. 3D
+   * cursor location).  */
   float loc[3], rot[3];
+};
+
+static std::optional<CollectionAddInfo> collection_add_info_get_from_op(bContext *C,
+                                                                        wmOperator *op)
+{
+  CollectionAddInfo add_info{};
+
+  Main *bmain = CTX_data_main(C);
 
-  PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
   PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
   PropertyRNA *prop_session_uuid = RNA_struct_find_property(op->ptr, "session_uuid");
+  PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
 
   bool update_location_if_necessary = false;
-  if (RNA_property_is_set(op->ptr, prop_name)) {
+  if (prop_name && RNA_property_is_set(op->ptr, prop_name)) {
     char name[MAX_ID_NAME - 2];
     RNA_property_string_get(op->ptr, prop_name, name);
-    collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
+    add_info.collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
     update_location_if_necessary = true;
   }
   else if (RNA_property_is_set(op->ptr, prop_session_uuid)) {
     const uint32_t session_uuid = (uint32_t)RNA_property_int_get(op->ptr, prop_session_uuid);
-    collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
+    add_info.collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
     update_location_if_necessary = true;
   }
   else {
-    collection = static_cast<Collection *>(
+    add_info.collection = static_cast<Collection *>(
         BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")));
   }
 
   if (update_location_if_necessary) {
     int mval[2];
     if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
-      ED_object_location_from_view(C, loc);
-      ED_view3d_cursor3d_position(C, mval, false, loc);
-      RNA_property_float_set_array(op->ptr, prop_location, loc);
+      ED_object_location_from_view(C, add_info.loc);
+      ED_view3d_cursor3d_position(C, mval, false, add_info.loc);
+      RNA_property_float_set_array(op->ptr, prop_location, add_info.loc);
     }
   }
 
-  if (collection == nullptr) {
-    return OPERATOR_CANCELLED;
+  if (add_info.collection == nullptr) {
+    return std::nullopt;
   }
 
-  if (!ED_object_add_generic_get_opts(
-          C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr)) {
-    return OPERATOR_CANCELLED;
+  if (!ED_object_add_generic_get_opts(C,
+                                      op,
+                                      'Z',
+                                      add_info.loc,
+                                      add_info.rot,
+                                      nullptr,
+                                      nullptr,
+                                      &add_info.local_view_bits,
+                                      nullptr)) {
+    return std::nullopt;
   }
 
   ViewLayer *view_layer = CTX_data_view_layer(C);
 
   /* Avoid dependency cycles. */
   LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
-  while (BKE_collection_cycle_find(active_lc->collection, collection)) {
+  while (BKE_collection_cycle_find(active_lc->collection, add_info.collection)) {
     active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
   }
 
-  Object *ob = ED_object_add_type(
-      C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits);
-  ob->instance_collection = collection;
+  return add_info;
+}
+
+static int collection_instance_add_exec(bContext *C, wmOperator *op)
+{
+  std::optional<CollectionAddInfo> add_info = collection_add_info_get_from_op(C, op);
+  if (!add_info) {
+    return OPERATOR_CANCELLED;
+  }
+
+  Object *ob = ED_object_add_type(C,
+                                  OB_EMPTY,
+                                  add_info->collection->id.name + 2,
+                                  add_info->loc,
+                                  add_info->rot,
+                                  false,
+                                  add_info->local_view_bits);
+  ob->instance_collection = add_info->collection;
   ob->empty_drawsize = U.collection_instance_empty_size;
   ob->transflag |= OB_DUPLICOLLECTION;
-  id_us_plus(&collection->id);
+  id_us_plus(&add_info->collection->id);
 
   return OPERATOR_FINISHED;
 }
@@ -1749,6 +1784,128 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Collection Drop Operator
+ *
+ * Internal operator for collection dropping.
+ *
+ * \warning This is tied closely together to the drop-box callbacks, so it shouldn't be used on its
+ *          own.
+ *
+ * The drop-box callback imports the collection, links it into the view-layer, selects all imported
+ * objects (which may include peripheral objects like parents or boolean-objects of an object in
+ * the collection) and activates one. Only the callback has enough info to do this reliably. Based
+ * on the instancing operator option, this operator then does one of two things:
+ * - Instancing enabled: Unlink the collection again, and instead add a collection instance empty
+ *   at the drop position.
+ * - Instancing disabled: Transform the objects to the drop position, keeping all relative
+ *   transforms of the objects to each other as is.
+ *
+ * \{ */
+
+static int collection_drop_exec(bContext *C, wmOperator *op)
+{
+  Main *bmain = CTX_data_main(C);
+  LayerCollection *active_collection = CTX_data_layer_collection(C);
+  std::optional<CollectionAddInfo> add_info = collection_add_info_get_from_op(C, op);
+  if (!add_info) {
+    return OPERATOR_CANCELLED;
+  }
+
+  if (RNA_boolean_get(op->ptr, "use_instance")) {
+    BKE_collection_child_remove(bmain, active_collection->collection, add_info->collection);
+    DEG_id_tag_update(&active_collection->collection->id, ID_RECALC_COPY_ON_WRITE);
+    DEG_relations_tag_update(bmain);
+
+    Object *ob = ED_object_add_type(C,
+                                    OB_EMPTY,
+                                    add_info->collection->id.name + 2,
+                                    add_info->loc,
+                                    add_info->rot,
+                                    false,
+                                    add_info->local_view_bits);
+    ob->instance_collection = add_info->collection;
+    ob->empty_drawsize = U.collection_instance_empty_size;
+    ob->transflag |= OB_DUPLICOLLECTION;
+    id_us_plus(&add_info->collection->id);
+  }
+  else {
+    ViewLayer *view_layer = CTX_data_view_layer(C);
+    float delta_mat[4][4];
+    unit_m4(delta_mat);
+
+    const float scale[3] = {1.0f, 1.0f, 1.0f};
+    loc_eul_size_to_mat4(delta_mat, add_info->loc, add_info->rot, scale);
+
+    float offset[3];
+    /* Reverse apply the instance offset, so toggling the Instance option doesn't cause the
+     * collection to jump. */
+    negate_v3_v3(offset, add_info->collection->instance_offset);
+    translate_m4(delta_mat, UNPACK3(offset));
+
+    ObjectsInViewLayerParams params = {0};
+    uint objects_len;
+    Object **objects = BKE_view_layer_array_selected_objects_params(
+        view_layer, nullptr, &objects_len, &params);
+    ED_object_xform_array_m4(objects, objects_len, delta_mat);
+
+    MEM_freeN(objects);
+  }
+
+  return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_external_asset_drop(wmOperatorType *ot)
+{
+  PropertyRNA *prop;
+
+  /* identifiers */
+  /* Name should only be displayed in the drag tooltip. */
+  ot->name = "Add Collection";
+  ot->description = "Add the dragged collection to the scene";
+  ot->idname = "OBJECT_OT_collection_external_asset_drop";
+
+  /* api callbacks */
+  ot->invoke = object_instance_add_invoke;
+  ot->exec = collection_drop_exec;
+  ot->poll = ED_operator_objectmode;
+
+  /* flags */
+  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+  /* properties */
+  prop = RNA_def_int(ot->srna,
+                     "session_uuid",
+                     0,
+                     INT32_MIN,
+                     INT32_MAX,
+                     "Session UUID",
+                     "Session UUID of the collection to add",
+                     INT32_MIN,
+                     INT32_MAX);
+  RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
+
+  ED_object_add_generic_props(ot, false);
+
+  /* Important: Instancing option. Intentionally remembered across executions (no #PROP_SKIP_SAVE).
+   */
+  RNA_def_boolean(ot->srna,
+                  "use_instance",
+                  true,
+                  "Instance",
+                  "Add the dropped collection as collection instance");
+
+  object_add_drop_xy_props(ot);
+
+  prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "");
+  RNA_def_enum_funcs(prop, RNA_collection_itemf);
+  RNA_def_property_flag(prop,
+                        (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE));
+  ot->prop = prop;
+}
+
+/** \} */
+
 /* --------------------------------

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list