diff options
-rw-r--r-- | doc/python_api/examples/bpy.types.Depsgraph.7.py | 64 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_curve.h | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_displist.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_object.h | 16 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve_convert.c | 81 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/displist.c | 24 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 20 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_types.h | 9 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_object_api.c | 46 |
10 files changed, 270 insertions, 10 deletions
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.7.py b/doc/python_api/examples/bpy.types.Depsgraph.7.py new file mode 100644 index 00000000000..61209a6b9d2 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Depsgraph.7.py @@ -0,0 +1,64 @@ +""" +Dependency graph: Object.to_curve() ++++++++++++++++++++++++++++++++++++ + +Function to get a curve from text and curve objects. It is typically used by exporters, render +engines, and tools that need to access the curve representing the object. + +The function takes the evaluated dependency graph as a required parameter and optionally a boolean +apply_modifiers which defaults to false. If apply_modifiers is true and the object is a curve object, +the spline deform modifiers are applied on the control points. Note that constructive modifiers and +modifiers that are not spline-enabled will not be applied. So modifiers like Array will not be applied +and deform modifiers that have Apply On Spline disabled will not be applied. + +If the object is a text object. The text will be converted into a 3D curve and returned. Modifiers are +never applied on text objects and apply_modifiers will be ignored. If the object is neither a curve nor +a text object, an error will be reported. + +.. note:: The resulting curve is owned by the object. It can be freed by calling `object.to_curve_clear()`. +.. note:: + The resulting curve must be treated as temporary, and can not be referenced from objects in the main + database. +""" +import bpy + + +class OBJECT_OT_object_to_curve(bpy.types.Operator): + """Convert selected object to curve and show number of splines""" + bl_label = "DEG Object to Curve" + bl_idname = "object.object_to_curve" + + def execute(self, context): + # Access input original object. + obj = context.object + if obj is None: + self.report({'INFO'}, "No active object to convert to curve") + return {'CANCELLED'} + if obj.type not in {'CURVE', 'FONT'}: + self.report({'INFO'}, "Object can not be converted to curve") + return {'CANCELLED'} + depsgraph = context.evaluated_depsgraph_get() + # Invoke to_curve() without applying modifiers. + curve_without_modifiers = obj.to_curve(depsgraph) + self.report({'INFO'}, f"{len(curve_without_modifiers.splines)} splines in a new curve without modifiers.") + # Remove temporary curve. + obj.to_curve_clear() + # Invoke to_curve() with applying modifiers. + curve_with_modifiers = obj.to_curve(depsgraph, apply_modifiers = True) + self.report({'INFO'}, f"{len(curve_with_modifiers.splines)} splines in new curve with modifiers.") + # Remove temporary curve. + obj.to_curve_clear() + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_object_to_curve) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_object_to_curve) + + +if __name__ == "__main__": + register() + diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 881b93fe709..660e7c08062 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -338,6 +338,18 @@ void BKE_curve_deform_co(const struct Object *ob_curve, /** \} */ +/* curve_convert.c */ + +/* Create a new curve from the given object at its current state. This only works for curve and + * text objects, otherwise NULL is returned. + * + * If apply_modifiers is true and the object is a curve one, then spline deform modifiers are + * applied on the control points of the splines. + */ +struct Curve *BKE_curve_new_from_object(struct Object *object, + struct Depsgraph *depsgraph, + bool apply_modifiers); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 83adbf6f1fd..05e60d38487 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -112,6 +112,13 @@ void BKE_displist_make_mball_forRender(struct Depsgraph *depsgraph, struct Object *ob, struct ListBase *dispbase); +bool BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct ListBase *source_nurb, + struct ListBase *target_nurb, + const bool for_render); + bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4); void BKE_displist_fill(const struct ListBase *dispbase, struct ListBase *to, diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 904db053717..12c40e891c9 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -32,6 +32,7 @@ extern "C" { struct Base; struct BoundBox; +struct Curve; struct Depsgraph; struct GpencilModifierData; struct HookGpencilModifierData; @@ -424,6 +425,21 @@ struct Mesh *BKE_object_to_mesh(struct Depsgraph *depsgraph, void BKE_object_to_mesh_clear(struct Object *object); +/* This is an utility function for Python's object.to_curve(). + * The result is owned by the object. + * + * The curve will be freed when object is re-evaluated or is destroyed. It is possible to force + * clear memory used by this curve by calling BKE_object_to_curve_clear(). + * + * If apply_modifiers is true and the object is a curve one, then spline deform modifiers are + * applied on the curve control points. + */ +struct Curve *BKE_object_to_curve(struct Object *object, + struct Depsgraph *depsgraph, + bool apply_modifiers); + +void BKE_object_to_curve_clear(struct Object *object); + void BKE_object_check_uuids_unique_and_report(const struct Object *object); void BKE_object_modifiers_lib_link_common(void *userData, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index f288bf9aabc..325744f4006 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -107,6 +107,7 @@ set(SRC intern/cryptomatte.cc intern/curve.c intern/curve_bevel.c + intern/curve_convert.c intern/curve_decimate.c intern/curve_deform.c intern/curveprofile.c diff --git a/source/blender/blenkernel/intern/curve_convert.c b/source/blender/blenkernel/intern/curve_convert.c new file mode 100644 index 00000000000..988ddb3bbc0 --- /dev/null +++ b/source/blender/blenkernel/intern/curve_convert.c @@ -0,0 +1,81 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + */ + +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_vfont_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_curve.h" +#include "BKE_displist.h" +#include "BKE_font.h" +#include "BKE_lib_id.h" +#include "BKE_modifier.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +static Curve *curve_from_font_object(Object *object, Depsgraph *depsgraph) +{ + Curve *curve = (Curve *)object->data; + Curve *new_curve = (Curve *)BKE_id_copy_ex(NULL, &curve->id, NULL, LIB_ID_COPY_LOCALIZE); + + Object *evaluated_object = DEG_get_evaluated_object(depsgraph, object); + BKE_vfont_to_curve_nubase(evaluated_object, FO_EDIT, &new_curve->nurb); + + new_curve->type = OB_CURVE; + + new_curve->flag &= ~CU_3D; + BKE_curve_curve_dimension_update(new_curve); + + return new_curve; +} + +static Curve *curve_from_curve_object(Object *object, Depsgraph *depsgraph, bool apply_modifiers) +{ + Object *evaluated_object = DEG_get_evaluated_object(depsgraph, object); + Curve *curve = (Curve *)evaluated_object->data; + Curve *new_curve = (Curve *)BKE_id_copy_ex(NULL, &curve->id, NULL, LIB_ID_COPY_LOCALIZE); + + if (apply_modifiers) { + BKE_curve_calc_modifiers_pre(depsgraph, + DEG_get_input_scene(depsgraph), + evaluated_object, + BKE_curve_nurbs_get(curve), + &new_curve->nurb, + DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + } + + return new_curve; +} + +Curve *BKE_curve_new_from_object(Object *object, Depsgraph *depsgraph, bool apply_modifiers) +{ + if (!ELEM(object->type, OB_FONT, OB_CURVE)) { + return NULL; + } + + if (object->type == OB_FONT) { + return curve_from_font_object(object, depsgraph); + } + + return curve_from_curve_object(object, depsgraph, apply_modifiers); +} diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 1fcc1b1bcef..c860e57520d 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -770,8 +770,12 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, } /* Return true if any modifier was applied. */ -static bool curve_calc_modifiers_pre( - Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render) +bool BKE_curve_calc_modifiers_pre(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + ListBase *source_nurb, + ListBase *target_nurb, + const bool for_render) { VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); @@ -810,13 +814,13 @@ static bool curve_calc_modifiers_pre( keyVerts = BKE_key_evaluate_object(ob, &numElems); if (keyVerts) { - BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems); + BLI_assert(BKE_keyblock_curve_element_count(source_nurb) == numElems); /* split coords from key data, the latter also includes * tilts, which is passed through in the modifier stack. * this is also the reason curves do not use a virtual * shape key modifier yet. */ - deformedVerts = BKE_curve_nurbs_key_vert_coords_alloc(nurb, keyVerts, &numVerts); + deformedVerts = BKE_curve_nurbs_key_vert_coords_alloc(source_nurb, keyVerts, &numVerts); } } @@ -832,7 +836,7 @@ static bool curve_calc_modifiers_pre( } if (!deformedVerts) { - deformedVerts = BKE_curve_nurbs_vert_coords_alloc(nurb, &numVerts); + deformedVerts = BKE_curve_nurbs_vert_coords_alloc(source_nurb, &numVerts); } mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts); @@ -845,11 +849,11 @@ static bool curve_calc_modifiers_pre( } if (deformedVerts) { - BKE_curve_nurbs_vert_coords_apply(nurb, deformedVerts, false); + BKE_curve_nurbs_vert_coords_apply(target_nurb, deformedVerts, false); MEM_freeN(deformedVerts); } if (keyVerts) { /* these are not passed through modifier stack */ - BKE_curve_nurbs_key_vert_tilts_apply(nurb, keyVerts); + BKE_curve_nurbs_key_vert_tilts_apply(target_nurb, keyVerts); } if (keyVerts) { @@ -1151,7 +1155,8 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, } if (!for_orco) { - force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = BKE_curve_calc_modifiers_pre( + depsgraph, scene, ob, &nubase, &nubase, for_render); } LISTBASE_FOREACH (Nurb *, nu, &nubase) { @@ -1501,7 +1506,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } if (!for_orco) { - force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = BKE_curve_calc_modifiers_pre( + depsgraph, scene, ob, &nubase, &nubase, for_render); } BKE_curve_bevelList_make(ob, &nubase, for_render); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 9b5a1614dc0..04071282a52 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1742,6 +1742,7 @@ void BKE_object_free_derived_caches(Object *ob) } BKE_object_to_mesh_clear(ob); + BKE_object_to_curve_clear(ob); BKE_object_free_curve_cache(ob); /* Clear grease pencil data. */ @@ -5057,6 +5058,7 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag)) runtime->mesh_deform_eval = NULL; runtime->curve_cache = NULL; runtime->object_as_temp_mesh = NULL; + runtime->object_as_temp_curve = NULL; runtime->geometry_set_eval = NULL; } @@ -5615,6 +5617,24 @@ void BKE_object_to_mesh_clear(Object *object) object->runtime.object_as_temp_mesh = NULL; } +Curve *BKE_object_to_curve(Object *object, Depsgraph *depsgraph, bool apply_modifiers) +{ + BKE_object_to_curve_clear(object); + + Curve *curve = BKE_curve_new_from_object(object, depsgraph, apply_modifiers); + object->runtime.object_as_temp_curve = curve; + return curve; +} + +void BKE_object_to_curve_clear(Object *object) +{ + if (object->runtime.object_as_temp_curve == NULL) { + return; + } + BKE_id_free(NULL, object->runtime.object_as_temp_curve); + object->runtime.object_as_temp_curve = NULL; +} + void BKE_object_check_uuids_unique_and_report(const Object *object) { BKE_pose_check_uuids_unique_and_report(object->pose); diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 8b13db8a012..5f414aa2bdd 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -38,6 +38,7 @@ extern "C" { struct AnimData; struct BoundBox; +struct Curve; struct FluidsimSettings; struct GeometrySet; struct Ipo; @@ -186,6 +187,12 @@ typedef struct Object_Runtime { */ struct Mesh *object_as_temp_mesh; + /** + * This is a curve representation of corresponding object. + * It created when Python calls `object.to_curve()`. + */ + struct Curve *object_as_temp_curve; + /** Runtime evaluated curve-specific data, not stored in the file. */ struct CurveCache *curve_cache; @@ -623,7 +630,7 @@ enum { */ #define BA_TRANSFORM_LOCKED_IN_PLACE (1 << 7) -#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */ +#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */ #define BA_TRANSFORM_PARENT (1 << 13) /* parent of a transformed object */ #define OB_FROMDUPLI (1 << 9) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 9fb883568c9..df628caa000 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -404,6 +404,29 @@ static void rna_Object_to_mesh_clear(Object *object) BKE_object_to_mesh_clear(object); } +static Curve *rna_Object_to_curve(Object *object, + ReportList *reports, + Depsgraph *depsgraph, + bool apply_modifiers) +{ + if (!ELEM(object->type, OB_FONT, OB_CURVE)) { + BKE_report(reports, RPT_ERROR, "Object is not a curve or a text"); + return NULL; + } + + if (depsgraph == NULL) { + BKE_report(reports, RPT_ERROR, "Invalid depsgraph"); + return NULL; + } + + return BKE_object_to_curve(object, depsgraph, apply_modifiers); +} + +static void rna_Object_to_curve_clear(Object *object) +{ + BKE_object_to_curve_clear(object); +} + static PointerRNA rna_Object_shape_key_add( Object *ob, bContext *C, ReportList *reports, const char *name, bool from_mix) { @@ -977,6 +1000,29 @@ void RNA_api_object(StructRNA *srna) func = RNA_def_function(srna, "to_mesh_clear", "rna_Object_to_mesh_clear"); RNA_def_function_ui_description(func, "Clears mesh data-block created by to_mesh()"); + /* curve */ + func = RNA_def_function(srna, "to_curve", "rna_Object_to_curve"); + RNA_def_function_ui_description( + func, + "Create a Curve data-block from the current state of the object. This only works for curve " + "and text objects. The object owns the data-block. To force free it, use to_curve_clear(). " + "The result is temporary and can not be used by objects from the main database"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer( + func, "depsgraph", "Depsgraph", "Dependency Graph", "Evaluated dependency graph"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, + "apply_modifiers", + false, + "", + "Apply the deform modifiers on the control points of the curve. This is only " + "supported for curve objects"); + parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve created from object"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "to_curve_clear", "rna_Object_to_curve_clear"); + RNA_def_function_ui_description(func, "Clears curve data-block created by to_curve()"); + /* Armature */ func = RNA_def_function(srna, "find_armature", "BKE_modifiers_is_deformed_by_armature"); RNA_def_function_ui_description( |