Fix #121356: GPv3: Conversion operators to/from Curves
Adds object conversion between Grease Pencil and Curves types. GPv3 object is converted to Curves by combining all visible layers at the current frame. Curves object is converted to Grease Pencil by constructing a new layer and keyframe with the curves geometry. The type enum for the conversion operator gets a dynamic function to check for the experimental flags and only show the enabled Grease Pencil object types. It does not currently exclude unsupported type combinations. Pull Request: https://projects.blender.org/blender/blender/pulls/122304
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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<GreasePencilDrawing *>(grease_pencil_dst->drawing_array[i])
|
||||
->wrap());
|
||||
break;
|
||||
case GP_DRAWING_REFERENCE:
|
||||
MEM_delete(&reinterpret_cast<GreasePencilDrawingReference *>(
|
||||
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<GreasePencilDrawing *>(grease_pencil_src->drawing_array[i])->wrap();
|
||||
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
|
||||
MEM_new<Drawing>(__func__, src_drawing));
|
||||
break;
|
||||
}
|
||||
case GP_DRAWING_REFERENCE:
|
||||
const DrawingReference &src_drawing_ref = reinterpret_cast<GreasePencilDrawingReference *>(
|
||||
grease_pencil_src->drawing_array[i])
|
||||
->wrap();
|
||||
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
|
||||
MEM_new<DrawingReference>(__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<bke::greasepencil::LayerGroup>(
|
||||
__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,
|
||||
|
||||
@@ -9,6 +9,7 @@ set(INC
|
||||
../../blentranslation
|
||||
../../bmesh
|
||||
../../functions
|
||||
../../geometry
|
||||
../../gpencil_modifiers_legacy
|
||||
../../gpu
|
||||
../../ikplugin
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#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<Curve *>(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<Curves *>(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<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(*scene, *grease_pencil, false);
|
||||
Array<bke::GeometrySet> geometries(drawings.size());
|
||||
for (const int i : drawings.index_range()) {
|
||||
Curves *curves_id = static_cast<Curves *>(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<Curves *>(newob->data);
|
||||
id_us_min(&curves->id);
|
||||
|
||||
newob->data = BKE_id_copy(bmain, &curves->id);
|
||||
}
|
||||
else {
|
||||
newob = ob;
|
||||
}
|
||||
|
||||
GreasePencil *new_grease_pencil = static_cast<GreasePencil *>(
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user