diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2020-06-16 16:28:46 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2020-06-16 16:28:46 +0300 |
commit | bc7a4b126afb6789e301c148d8f07e38365c1545 (patch) | |
tree | a82f5af312381b55d355dab2af39b73503696b15 /source/blender/editors | |
parent | e54058b1212202f5386ab53336e32ed01c441126 (diff) |
GPencil: Convert and Bake mesh animation to grease pencil strokes
This patch adds two options:
- Convert a mesh to grease pencil strokes.
- Bake the mesh animation into grease pencil strokes.
Both are related and must be included in the same patch.
Related to tasks: T77629 and T77630
Notice: The conversion is done for mesh edges and it's not considering any visibility clipping. All edges are exported, no matters if it's visible or not.
Example of Convert a Mesh to Grease Pencil strokes:
{F8606028}
This conversion was inspired by the technique used by @luamono in this tweet: https://twitter.com/luamono/status/1239983662176841730
Example of Bake Animation (the video is a little outdate, but the basic functionality is the same, only small changes in UI):
{F8606032}
Reviewed By: mendio, pepeland
Maniphest Tasks: T77629, T77630
Differential Revision: https://developer.blender.org/D7983
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/gpencil/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_convert.c | 2 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_mesh.c | 404 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_ops.c | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_add.c | 126 |
6 files changed, 525 insertions, 11 deletions
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 4083169d65c..735ad8bc039 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC gpencil_fill.c gpencil_interpolate.c gpencil_merge.c + gpencil_mesh.c gpencil_ops.c gpencil_ops_versioning.c gpencil_paint.c diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 78a34cda2f5..f1b8ae61994 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -54,8 +54,10 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 473913c5459..bc46842bb3b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -485,6 +485,8 @@ void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot); void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); +void GPENCIL_OT_bake_mesh_animation(struct wmOperatorType *ot); + void GPENCIL_OT_image_to_grease_pencil(struct wmOperatorType *ot); enum { diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c new file mode 100644 index 00000000000..ffb12404b43 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -0,0 +1,404 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * Operator for converting Grease Pencil data to geometry + */ + +/** \file + * \ingroup edgpencil + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "DNA_gpencil_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" +#include "BKE_duplilist.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_gpencil.h" +#include "ED_transform_snap_object_context.h" + +#include "gpencil_intern.h" + +/* Check frame_end is always > start frame! */ +static void gp_bake_set_frame_end(struct Main *UNUSED(main), + struct Scene *UNUSED(scene), + struct PointerRNA *ptr) +{ + int frame_start = RNA_int_get(ptr, "frame_start"); + int frame_end = RNA_int_get(ptr, "frame_end"); + + if (frame_end <= frame_start) { + RNA_int_set(ptr, "frame_end", frame_start + 1); + } +} + +/* Extract mesh animation to Grease Pencil. */ +static bool gp_bake_mesh_animation_poll(bContext *C) +{ + if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) { + return false; + } + + /* Only if the current view is 3D View. */ + ScrArea *area = CTX_wm_area(C); + return (area && area->spacetype); +} + +typedef struct GpBakeOb { + struct GPBakelist *next, *prev; + Object *ob; +} GpBakeOb; + +static void gp_bake_duplilist(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *list) +{ + GpBakeOb *elem = NULL; + ListBase *lb; + DupliObject *dob; + lb = object_duplilist(depsgraph, scene, ob); + for (dob = lb->first; dob; dob = dob->next) { + if (dob->ob->type != OB_MESH) { + continue; + } + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = dob->ob; + BLI_addtail(list, elem); + } + + free_object_duplilist(lb); +} + +static void gp_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene, ListBase *list) +{ + GpBakeOb *elem = NULL; + + /* Add active object. In some files this could not be in selected array. */ + Object *obact = CTX_data_active_object(C); + + if (obact->type == OB_MESH) { + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = obact; + BLI_addtail(list, elem); + } + /* Add duplilist. */ + else if (obact->type == OB_EMPTY) { + gp_bake_duplilist(depsgraph, scene, obact, list); + } + + /* Add other selected objects. */ + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob == obact) { + continue; + } + /* Add selected meshes.*/ + if (ob->type == OB_MESH) { + elem = MEM_callocN(sizeof(GpBakeOb), __func__); + elem->ob = ob; + BLI_addtail(list, elem); + } + + /* Add duplilist. */ + if (ob->type == OB_EMPTY) { + gp_bake_duplilist(depsgraph, scene, obact, list); + } + } + CTX_DATA_END; +} + +static void gp_bake_free_ob_list(ListBase *list) +{ + LISTBASE_FOREACH_MUTABLE (GpBakeOb *, elem, list) { + MEM_SAFE_FREE(elem); + } +} + +static int gp_bake_mesh_animation_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + Object *ob_gpencil = NULL; + + ListBase list = {NULL, NULL}; + gp_bake_ob_list(C, depsgraph, scene, &list); + + /* Cannot check this in poll because the active object changes. */ + if (list.first == NULL) { + BKE_report(op->reports, RPT_INFO, "No valid object selected"); + gp_bake_free_ob_list(&list); + return OPERATOR_CANCELLED; + } + + /* Grab all relevant settings. */ + const int step = RNA_int_get(op->ptr, "step"); + + const int frame_start = (scene->r.sfra > RNA_int_get(op->ptr, "frame_start")) ? + scene->r.sfra : + RNA_int_get(op->ptr, "frame_start"); + + const int frame_end = (scene->r.efra < RNA_int_get(op->ptr, "frame_end")) ? + scene->r.efra : + RNA_int_get(op->ptr, "frame_end"); + + const float angle = RNA_float_get(op->ptr, "angle"); + const int thickness = RNA_int_get(op->ptr, "thickness"); + const bool use_seams = RNA_boolean_get(op->ptr, "seams"); + const bool use_faces = RNA_boolean_get(op->ptr, "faces"); + const float offset = RNA_float_get(op->ptr, "offset"); + const int frame_offset = RNA_int_get(op->ptr, "frame_target") - frame_start; + char target[64]; + RNA_string_get(op->ptr, "target", target); + const int project_type = RNA_enum_get(op->ptr, "project_type"); + + /* Create a new grease pencil object in origin. */ + bool newob = false; + if (STREQ(target, "*NEW")) { + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + float loc[3] = {0.0f, 0.0f, 0.0f}; + ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); + newob = true; + } + else { + ob_gpencil = BLI_findstring(&bmain->objects, target, offsetof(ID, name) + 2); + } + + if ((ob_gpencil == NULL) || (ob_gpencil->type != OB_GPENCIL)) { + BKE_report(op->reports, RPT_ERROR, "Target grease pencil object not valid"); + gp_bake_free_ob_list(&list); + return OPERATOR_CANCELLED; + } + + bGPdata *gpd = (bGPdata *)ob_gpencil->data; + gpd->draw_mode = (project_type == GP_REPROJECT_KEEP) ? GP_DRAWMODE_3D : GP_DRAWMODE_2D; + + /* Set cursor to indicate working. */ + WM_cursor_wait(1); + + GP_SpaceConversion gsc = {NULL}; + SnapObjectContext *sctx = NULL; + if (project_type != GP_REPROJECT_KEEP) { + /* Init space conversion stuff. */ + gp_point_conversion_init(C, &gsc); + /* Init snap context for geometry projection. */ + sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C)); + + /* Tag all existing strokes to avoid reprojections. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag |= GP_STROKE_TAG; + } + } + } + } + + /* Loop all frame range. */ + int oldframe = (int)DEG_get_ctime(depsgraph); + int key = -1; + for (int i = frame_start; i < frame_end + 1; i++) { + key++; + /* Jump if not step limit but include last frame always. */ + if ((key % step != 0) && (i != frame_end)) { + continue; + } + + /* Move scene to new frame. */ + CFRA = i; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* Loop all objects in the list. */ + LISTBASE_FOREACH (GpBakeOb *, elem, &list) { + Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, elem->ob); + + /* Generate strokes. */ + BKE_gpencil_convert_mesh(bmain, + depsgraph, + scene, + ob_gpencil, + elem->ob, + angle, + thickness, + offset, + ob_eval->obmat, + frame_offset, + use_seams, + use_faces); + + /* Reproject all untaged created strokes. */ + if (project_type != GP_REPROJECT_KEEP) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = gpl->actframe; + if (gpf != NULL) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if ((gps->flag & GP_STROKE_TAG) == 0) { + ED_gpencil_stroke_reproject( + depsgraph, &gsc, sctx, gpl, gpf, gps, project_type, false); + gps->flag |= GP_STROKE_TAG; + } + } + } + } + } + } + } + + /* Return scene frame state and DB to original state. */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* Remove unused materials. */ + int actcol = ob_gpencil->actcol; + for (int slot = 1; slot <= ob_gpencil->totcol; slot++) { + while (slot <= ob_gpencil->totcol && !BKE_object_material_slot_used(ob_gpencil->data, slot)) { + ob_gpencil->actcol = slot; + BKE_object_material_slot_remove(CTX_data_main(C), ob_gpencil); + + if (actcol >= slot) { + actcol--; + } + } + } + ob_gpencil->actcol = actcol; + + /* Untag all strokes. */ + if (project_type != GP_REPROJECT_KEEP) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag &= ~GP_STROKE_TAG; + } + } + } + } + + /* Free memory. */ + gp_bake_free_ob_list(&list); + if (sctx != NULL) { + ED_transform_snap_object_context_destroy(sctx); + } + + /* notifiers */ + if (newob) { + DEG_relations_tag_update(bmain); + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + /* Reset cursor. */ + WM_cursor_wait(0); + + /* done */ + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_bake_mesh_animation(wmOperatorType *ot) +{ + static const EnumPropertyItem reproject_type[] = { + {GP_REPROJECT_KEEP, "KEEP", 0, "No Reproject", ""}, + {GP_REPROJECT_FRONT, "FRONT", 0, "Front", "Reproject the strokes using the X-Z plane"}, + {GP_REPROJECT_SIDE, "SIDE", 0, "Side", "Reproject the strokes using the Y-Z plane"}, + {GP_REPROJECT_TOP, "TOP", 0, "Top", "Reproject the strokes using the X-Y plane"}, + {GP_REPROJECT_VIEW, + "VIEW", + 0, + "View", + "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " + "using 'Cursor' Stroke Placement"}, + {GP_REPROJECT_CURSOR, + "CURSOR", + 0, + "Cursor", + "Reproject the strokes using the orientation of 3D cursor"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bake Mesh Animation to Grease Pencil"; + ot->idname = "GPENCIL_OT_bake_mesh_animation"; + ot->description = "Bake Mesh Animation to Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gp_bake_mesh_animation_exec; + ot->poll = gp_bake_mesh_animation_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_int( + ot->srna, "frame_start", 1, 1, 100000, "Start Frame", "The start frame", 1, 100000); + + prop = RNA_def_int( + ot->srna, "frame_end", 250, 1, 100000, "End Frame", "The end frame of animation", 1, 100000); + RNA_def_property_update_runtime(prop, gp_bake_set_frame_end); + + prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Step", "Step between generated frames", 1, 100); + + prop = RNA_def_float_rotation(ot->srna, + "angle", + 0, + NULL, + DEG2RADF(0.0f), + DEG2RADF(180.0f), + "Threshold Angle", + "Threshold to determine ends of the strokes", + DEG2RADF(0.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(70.0f)); + + RNA_def_int(ot->srna, "thickness", 1, 1, 100, "Thickness", "", 1, 100); + RNA_def_boolean(ot->srna, "seams", 0, "Only Seam Edges", "Convert only seam edges"); + RNA_def_boolean(ot->srna, "faces", 1, "Export Faces", "Export faces as filled strokes"); + RNA_def_float_distance( + ot->srna, "offset", 0.001f, 0.0, 100.0, "Offset", "Offset strokes from fill", 0.0, 100.00); + RNA_def_int(ot->srna, "frame_target", 1, 1, 100000, "Frame Target", "", 1, 100000); + RNA_def_string(ot->srna, + "target", + "*NEW", + 64, + "Target Object", + "Target grease pencil object name. Leave empty for new object"); + + RNA_def_enum(ot->srna, "project_type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", ""); +} diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 94c86572fd3..7b92426efd4 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -603,6 +603,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_frame_clean_loose); WM_operatortype_append(GPENCIL_OT_convert); + WM_operatortype_append(GPENCIL_OT_bake_mesh_animation); WM_operatortype_append(GPENCIL_OT_image_to_grease_pencil); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8289f52b0c8..7dfca69d7f0 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -65,6 +65,7 @@ #include "BKE_effect.h" #include "BKE_font.h" #include "BKE_gpencil_curve.h" +#include "BKE_gpencil_geom.h" #include "BKE_hair.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -96,6 +97,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "UI_interface.h" + #include "WM_api.h" #include "WM_types.h" @@ -2129,7 +2132,7 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) static const EnumPropertyItem convert_target_items[] = { {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, {OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""}, - {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve", ""}, + {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve/Mesh", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2261,9 +2264,16 @@ static int convert_exec(bContext *C, wmOperator *op) Nurb *nu; MetaBall *mb; Mesh *me; - Object *gpencil_ob = NULL; + Object *ob_gpencil = NULL; const short target = RNA_enum_get(op->ptr, "target"); bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); + + const float angle = RNA_float_get(op->ptr, "angle"); + const int thickness = RNA_int_get(op->ptr, "thickness"); + const bool use_seams = RNA_boolean_get(op->ptr, "seams"); + const bool use_faces = RNA_boolean_get(op->ptr, "faces"); + const float offset = RNA_float_get(op->ptr, "offset"); + int a, mballConverted = 0; bool gpencilConverted = false; @@ -2375,6 +2385,54 @@ static int convert_exec(bContext *C, wmOperator *op) ED_rigidbody_object_remove(bmain, scene, newob); } } + else if (ob->type == OB_MESH && target == OB_GPENCIL) { + ob->flag |= OB_DONE; + + /* Create a new grease pencil object and copy transformations. */ + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + float loc[3], size[3], rot[3][3], eul[3]; + float matrix[4][4]; + mat4_to_loc_rot_size(loc, rot, size, ob->obmat); + mat3_to_eul(eul, rot); + + ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); + copy_v3_v3(ob_gpencil->loc, loc); + copy_v3_v3(ob_gpencil->rot, eul); + copy_v3_v3(ob_gpencil->scale, size); + unit_m4(matrix); + /* Set object in 3D mode. */ + bGPdata *gpd = (bGPdata *)ob_gpencil->data; + gpd->draw_mode = GP_DRAWMODE_3D; + + BKE_gpencil_convert_mesh(bmain, + depsgraph, + scene, + ob_gpencil, + ob, + angle, + thickness, + offset, + matrix, + 0, + use_seams, + use_faces); + gpencilConverted = true; + + /* Remove unused materials. */ + int actcol = ob_gpencil->actcol; + for (int slot = 1; slot <= ob_gpencil->totcol; slot++) { + while (slot <= ob_gpencil->totcol && + !BKE_object_material_slot_used(ob_gpencil->data, slot)) { + ob_gpencil->actcol = slot; + BKE_object_material_slot_remove(CTX_data_main(C), ob_gpencil); + + if (actcol >= slot) { + actcol--; + } + } + } + ob_gpencil->actcol = actcol; + } else if (ob->type == OB_MESH) { ob->flag |= OB_DONE; @@ -2509,10 +2567,10 @@ static int convert_exec(bContext *C, wmOperator *op) * Nurbs Surface are not supported. */ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; - gpencil_ob = ED_gpencil_add_object(C, ob->loc, local_view_bits); - copy_v3_v3(gpencil_ob->rot, ob->rot); - copy_v3_v3(gpencil_ob->scale, ob->scale); - BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true); + ob_gpencil = ED_gpencil_add_object(C, ob->loc, local_view_bits); + copy_v3_v3(ob_gpencil->rot, ob->rot); + copy_v3_v3(ob_gpencil->scale, ob->scale); + BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, false, false, true); gpencilConverted = true; } } @@ -2618,12 +2676,12 @@ static int convert_exec(bContext *C, wmOperator *op) } FOREACH_SCENE_OBJECT_END; } - /* Remove curves converted to Grease Pencil object. */ + /* Remove curves and meshes converted to Grease Pencil object. */ if (gpencilConverted) { - FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) { - if (ob_curve->type == OB_CURVE) { - if (ob_curve->flag & OB_DONE) { - ED_object_base_free_and_unlink(bmain, scene, ob_curve); + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_delete) { + if ((ob_delete->type == OB_CURVE) || (ob_delete->type == OB_MESH)) { + if (ob_delete->flag & OB_DONE) { + ED_object_base_free_and_unlink(bmain, scene, ob_delete); } } } @@ -2652,8 +2710,28 @@ static int convert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void convert_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + uiItemR(layout, &ptr, "target", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "keep_original", 0, NULL, ICON_NONE); + + if (RNA_enum_get(&ptr, "target") == OB_GPENCIL) { + uiItemR(layout, &ptr, "thickness", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "seams", 0, NULL, ICON_NONE); + uiItemR(layout, &ptr, "faces", 0, NULL, ICON_NONE); + } +} + void OBJECT_OT_convert(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Convert to"; ot->description = "Convert selected objects to another type"; @@ -2663,6 +2741,7 @@ void OBJECT_OT_convert(wmOperatorType *ot) ot->invoke = WM_menu_invoke; ot->exec = convert_exec; ot->poll = convert_poll; + ot->ui = convert_ui; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2675,6 +2754,31 @@ void OBJECT_OT_convert(wmOperatorType *ot) 0, "Keep Original", "Keep original objects instead of replacing them"); + + prop = RNA_def_float_rotation(ot->srna, + "angle", + 0, + NULL, + DEG2RADF(0.0f), + DEG2RADF(180.0f), + "Threshold Angle", + "Threshold to determine ends of the strokes", + DEG2RADF(0.0f), + DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(70.0f)); + + RNA_def_int(ot->srna, "thickness", 5, 1, 100, "Thickness", "", 1, 100); + RNA_def_boolean(ot->srna, "seams", 0, "Only Seam Edges", "Convert only seam edges"); + RNA_def_boolean(ot->srna, "faces", 1, "Export Faces", "Export faces as filled strokes"); + RNA_def_float_distance(ot->srna, + "offset", + 0.01f, + 0.0, + OBJECT_ADD_SIZE_MAXF, + "Stroke Offset", + "Offset strokes from fill", + 0.0, + 100.00); } /** \} */ |