diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 474f1b7e4a4..42166844511 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -984,6 +984,12 @@ inline bool GreasePencil::has_active_group() const void *BKE_grease_pencil_add(Main *bmain, const char *name); GreasePencil *BKE_grease_pencil_new_nomain(); GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src); +/** + * Move data from a grease pencil outside of the main data-base into a grease pencil in the + * data-base. Takes ownership of the source mesh. */ +void BKE_grease_pencil_nomain_to_grease_pencil(GreasePencil *grease_pencil_src, + GreasePencil *grease_pencil_dst); + void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object); void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst); diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index fb26434a97b..f09f8e04c28 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -1735,6 +1735,67 @@ GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_ return grease_pencil; } +void BKE_grease_pencil_nomain_to_grease_pencil(GreasePencil *grease_pencil_src, + GreasePencil *grease_pencil_dst) +{ + using namespace blender; + using bke::greasepencil::Drawing; + using bke::greasepencil::DrawingReference; + + /* Drawings. */ + const int drawing_array_num = grease_pencil_src->drawing_array_num; + grease_pencil_dst->resize_drawings(drawing_array_num); + for (const int i : IndexRange(drawing_array_num)) { + if (grease_pencil_dst->drawing_array[i]) { + switch (grease_pencil_dst->drawing_array[i]->type) { + case GP_DRAWING: + MEM_delete(&reinterpret_cast(grease_pencil_dst->drawing_array[i]) + ->wrap()); + break; + case GP_DRAWING_REFERENCE: + MEM_delete(&reinterpret_cast( + grease_pencil_dst->drawing_array[i]) + ->wrap()); + break; + } + } + switch (grease_pencil_src->drawing_array[i]->type) { + case GP_DRAWING: { + const Drawing &src_drawing = + reinterpret_cast(grease_pencil_src->drawing_array[i])->wrap(); + grease_pencil_dst->drawing_array[i] = reinterpret_cast( + MEM_new(__func__, src_drawing)); + break; + } + case GP_DRAWING_REFERENCE: + const DrawingReference &src_drawing_ref = reinterpret_cast( + grease_pencil_src->drawing_array[i]) + ->wrap(); + grease_pencil_dst->drawing_array[i] = reinterpret_cast( + MEM_new(__func__, src_drawing_ref)); + break; + } + } + + /* Layers. */ + if (grease_pencil_dst->root_group_ptr) { + MEM_delete(&grease_pencil_dst->root_group()); + } + + grease_pencil_dst->root_group_ptr = MEM_new( + __func__, grease_pencil_src->root_group_ptr->wrap()); + BLI_assert(grease_pencil_src->layers().size() == grease_pencil_dst->layers().size()); + + CustomData_copy(&grease_pencil_src->layers_data, + &grease_pencil_dst->layers_data, + eCustomDataMask(CD_MASK_ALL), + grease_pencil_src->layers().size()); + + DEG_id_tag_update(&grease_pencil_dst->id, ID_RECALC_GEOMETRY); + + BKE_id_free(nullptr, grease_pencil_src); +} + static void grease_pencil_evaluate_modifiers(Depsgraph *depsgraph, Scene *scene, Object *object, diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 2b29f89ec5d..435a72f5440 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -9,6 +9,7 @@ set(INC ../../blentranslation ../../bmesh ../../functions + ../../geometry ../../gpencil_modifiers_legacy ../../gpu ../../ikplugin diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 4bcb4752338..0078f3621d9 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -11,6 +11,7 @@ #include #include +#include "BKE_curves.hh" #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" @@ -97,6 +98,8 @@ #include "DEG_depsgraph_build.hh" #include "DEG_depsgraph_query.hh" +#include "GEO_join_geometries.hh" + #include "RNA_access.hh" #include "RNA_define.hh" #include "RNA_enum_types.hh" @@ -3012,6 +3015,38 @@ static const EnumPropertyItem convert_target_items[] = { {0, nullptr, 0, nullptr, nullptr}, }; +static const EnumPropertyItem *convert_target_itemf(bContext *C, + PointerRNA * /*ptr*/, + PropertyRNA * /*prop*/, + bool *r_free) +{ + if (!C) { /* needed for docs */ + return convert_target_items; + } + + EnumPropertyItem *item = nullptr; + int totitem = 0; + + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_MESH); + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_CURVES_LEGACY); + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_CURVES); + if (U.experimental.use_new_point_cloud_type) { + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_POINTCLOUD); + } + if (U.experimental.use_grease_pencil_version3) { + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_GREASE_PENCIL); + } + else { + RNA_enum_items_add_value(&item, &totitem, convert_target_items, OB_GPENCIL_LEGACY); + } + + RNA_enum_item_end(&item, &totitem); + + *r_free = true; + + return item; +} + static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); @@ -3346,6 +3381,49 @@ static int object_convert_exec(bContext *C, wmOperator *op) BKE_object_free_derived_caches(newob); BKE_object_free_modifiers(newob, 0); } + else if (geometry.has_grease_pencil()) { + if (keep_original) { + basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, nullptr); + newob = basen->object; + + /* Decrement original curve's usage count. */ + Curve *legacy_curve = static_cast(newob->data); + id_us_min(&legacy_curve->id); + + /* Make a copy of the curve. */ + newob->data = BKE_id_copy(bmain, &legacy_curve->id); + } + else { + newob = ob; + } + + Curves *new_curves = static_cast(BKE_id_new(bmain, ID_CV, newob->id.name + 2)); + newob->data = new_curves; + newob->type = OB_CURVES; + + if (const Curves *curves_eval = geometry.get_curves()) { + new_curves->geometry.wrap() = curves_eval->geometry.wrap(); + BKE_object_material_from_eval_data(bmain, newob, &curves_eval->id); + } + else if (const GreasePencil *grease_pencil = geometry.get_grease_pencil()) { + const Vector drawings = + ed::greasepencil::retrieve_visible_drawings(*scene, *grease_pencil, false); + Array geometries(drawings.size()); + for (const int i : drawings.index_range()) { + Curves *curves_id = static_cast(BKE_id_new_nomain(ID_CV, nullptr)); + curves_id->geometry.wrap() = drawings[i].drawing.strokes(); + geometries[i] = bke::GeometrySet::from_curves(curves_id); + } + bke::GeometrySet joined_curves = geometry::join_geometries(geometries, {}); + + new_curves->geometry.wrap() = joined_curves.get_curves()->geometry.wrap(); + new_curves->geometry.wrap().tag_topology_changed(); + BKE_object_material_from_eval_data(bmain, newob, &joined_curves.get_curves()->id); + } + + BKE_object_free_derived_caches(newob); + BKE_object_free_modifiers(newob, 0); + } else { BKE_reportf( op->reports, RPT_WARNING, "Object '%s' has no evaluated curves data", ob->id.name + 2); @@ -3658,6 +3736,62 @@ static int object_convert_exec(bContext *C, wmOperator *op) BKE_object_free_derived_caches(newob); BKE_object_free_modifiers(newob, 0); } + else if (ob->type == OB_CURVES && target == OB_GREASE_PENCIL) { + ob->flag |= OB_DONE; + + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bke::GeometrySet geometry; + if (ob_eval->runtime->geometry_set_eval != nullptr) { + geometry = *ob_eval->runtime->geometry_set_eval; + } + + if (keep_original) { + basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, nullptr); + newob = basen->object; + + Curves *curves = static_cast(newob->data); + id_us_min(&curves->id); + + newob->data = BKE_id_copy(bmain, &curves->id); + } + else { + newob = ob; + } + + GreasePencil *new_grease_pencil = static_cast( + BKE_id_new(bmain, ID_GP, newob->id.name + 2)); + newob->data = new_grease_pencil; + newob->type = OB_GREASE_PENCIL; + + if (const GreasePencil *grease_pencil_eval = geometry.get_grease_pencil()) { + BKE_grease_pencil_nomain_to_grease_pencil( + BKE_grease_pencil_copy_for_eval(grease_pencil_eval), new_grease_pencil); + BKE_object_material_from_eval_data(bmain, newob, &grease_pencil_eval->id); + new_grease_pencil->attributes_for_write().remove_anonymous(); + } + else if (const Curves *curves_eval = geometry.get_curves()) { + GreasePencil *grease_pencil = BKE_grease_pencil_new_nomain(); + /* Insert a default layer and place the drawing on frame 1. */ + const std::string layer_name = "Layer"; + const int frame_number = 1; + bke::greasepencil::Layer &layer = grease_pencil->add_layer(layer_name); + bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, frame_number); + BLI_assert(drawing != nullptr); + drawing->strokes_for_write() = curves_eval->geometry.wrap(); + + BKE_grease_pencil_nomain_to_grease_pencil(grease_pencil, new_grease_pencil); + BKE_object_material_from_eval_data(bmain, newob, &curves_eval->id); + } + else { + BKE_reportf(op->reports, + RPT_WARNING, + "Object '%s' has no evaluated grease pencil or curves data", + ob->id.name + 2); + } + + BKE_object_free_derived_caches(newob); + BKE_object_free_modifiers(newob, 0); + } else { continue; } @@ -3807,8 +3941,10 @@ void OBJECT_OT_convert(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum( + ot->prop = prop = RNA_def_enum( ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to"); + RNA_def_enum_funcs(prop, convert_target_itemf); + prop = RNA_def_boolean(ot->srna, "keep_original", false,