From 3fa51df744ea5c4585e4cb53a207a0f106ec2032 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 31 Aug 2009 01:58:11 +0000 Subject: Grease Pencil: Restored some editing operators (convert and delete active frame) * Convert operator - can currently be used to convert active Grease Pencil layer to curves. I had a look at making this part of a special "curve sketching" macro, though it seems that we cannot have modal operators coming first in a macro (and also cannot specify operator calling modes) * Delete Active Frame operator - does what its name say it does. It deletes the active frame for the active layer of Grease Pencil sketches. --- source/blender/blenkernel/intern/gpencil.c | 2 +- source/blender/editors/gpencil/gpencil_buttons.c | 20 +- source/blender/editors/gpencil/gpencil_edit.c | 304 +++++++++++++++++++++++ source/blender/editors/gpencil/gpencil_intern.h | 4 + source/blender/editors/gpencil/gpencil_ops.c | 4 + 5 files changed, 324 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index b02128c3c68..43c4137e73e 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -313,7 +313,7 @@ bGPdata *gpencil_data_duplicate (bGPdata *src) void gpencil_frame_delete_laststroke (bGPDlayer *gpl, bGPDframe *gpf) { bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL; - int cfra = 1; // XXX FIXME!!! + int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */ /* error checking */ if (ELEM(NULL, gpf, gps)) diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c index 774f7b7162b..c3f779b59b8 100644 --- a/source/blender/editors/gpencil/gpencil_buttons.c +++ b/source/blender/editors/gpencil/gpencil_buttons.c @@ -203,6 +203,12 @@ static void gp_drawui_layer (uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl) subcol= uiLayoutColumn(col, 1); uiItemR(subcol, NULL, 0, &ptr, "line_thickness", UI_ITEM_R_SLIDER); + /* debugging options */ + if (G.f & G_DEBUG) { + subcol= uiLayoutColumn(col, 1); + uiItemR(subcol, NULL, 0, &ptr, "show_points", 0); + } + /* right column ................... */ col= uiLayoutColumn(split, 0); @@ -211,15 +217,10 @@ static void gp_drawui_layer (uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl) uiItemR(subcol, "Onion Skinning", 0, &ptr, "use_onion_skinning", 0); uiItemR(subcol, "GStep", 0, &ptr, "max_ghost_range", 0); // XXX shorter name here? (i.e. GStep) - /* debugging options */ - // XXX re-enable the debug-only checks later - //if (G.f & G_DEBUG) { - subcol= uiLayoutColumn(col, 1); - uiItemR(subcol, NULL, 0, &ptr, "show_points", 0); - //} - /* additional options... */ - // None at the moment... + subcol= uiLayoutColumn(col, 1); + uiItemO(subcol, "Delete Frame", 0, "GPENCIL_OT_active_frame_delete"); + uiItemO(subcol, "Convert...", 0, "GPENCIL_OT_convert"); } } @@ -237,7 +238,8 @@ static void draw_gpencil_panel (bContext *C, uiLayout *layout, bGPdata *gpd, Poi col= uiLayoutColumn(layout, 0); /* current Grease Pencil block */ // TODO: show some info about who owns this? - uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_new", "GPENCIL_OT_data_unlink"); + //uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_new", "GPENCIL_OT_data_unlink"); // XXX not working + uiItemR(col, NULL, 0, ctx_ptr, "grease_pencil", 0); // XXX this will have to do for now... /* add new layer button */ uiItemO(col, NULL, 0, "GPENCIL_OT_layer_add"); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 74fbe250d37..8cf1affa8c6 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -60,6 +60,7 @@ #include "BKE_gpencil.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_utildefines.h" @@ -70,6 +71,7 @@ #include "WM_types.h" #include "RNA_access.h" +#include "RNA_define.h" #include "UI_view2d.h" @@ -280,4 +282,306 @@ void GPENCIL_OT_layer_add (wmOperatorType *ot) ot->poll= gp_add_poll; } +/* ******************* Delete Active Frame ************************ */ + +static int gp_actframe_delete_poll (bContext *C) +{ + bGPdata *gpd= gpencil_data_get_active(C); + bGPDlayer *gpl= gpencil_layer_getactive(gpd); + + /* only if there's an active layer with an active frame */ + return (gpl && gpl->actframe); +} + +/* delete active frame - wrapper around API calls */ +static int gp_actframe_delete_exec (bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + bGPdata *gpd= gpencil_data_get_active(C); + bGPDlayer *gpl= gpencil_layer_getactive(gpd); + bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0); + + /* if there's no existing Grease-Pencil data there, add some */ + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + if ELEM(NULL, gpl, gpf) { + BKE_report(op->reports, RPT_ERROR, "No active frame to delete"); + return OPERATOR_CANCELLED; + } + + /* delete it... */ + gpencil_layer_delframe(gpl, gpf); + + /* notifiers */ + WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX please work! + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_active_frame_delete (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete Active Frame"; + ot->idname= "GPENCIL_OT_active_frame_delete"; + ot->description= "Delete the active frame for the active Grease Pencil datablock."; + + /* callbacks */ + ot->exec= gp_actframe_delete_exec; + ot->poll= gp_actframe_delete_poll; +} + +/* ************************************************ */ +/* Grease Pencil to Data Operator */ + +/* defines for possible modes */ +enum { + GP_STROKECONVERT_PATH = 1, + GP_STROKECONVERT_CURVE, +}; + +/* RNA enum define */ +static EnumPropertyItem prop_gpencil_convertmodes[] = { + {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""}, + {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""}, + {0, NULL, 0, NULL, NULL} +}; + +/* --- */ + +/* convert the coordinates from the given stroke point into 3d-coordinates + * - assumes that the active space is the 3D-View + */ +static void gp_strokepoint_convertcoords (bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3]) +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + ARegion *ar= CTX_wm_region(C); + + if (gps->flag & GP_STROKE_3DSPACE) { + /* directly use 3d-coordinates */ + VecCopyf(p3d, &pt->x); + } + else { + float *fp= give_cursor(scene, v3d); + float dvec[3]; + short mval[2]; + int mx, my; + + /* get screen coordinate */ + if (gps->flag & GP_STROKE_2DSPACE) { + View2D *v2d= &ar->v2d; + UI_view2d_view_to_region(v2d, pt->x, pt->y, &mx, &my); + } + else { + mx= (int)(pt->x / 100 * ar->winx); + my= (int)(pt->y / 100 * ar->winy); + } + mval[0]= (short)mx; + mval[1]= (short)my; + + /* convert screen coordinate to 3d coordinates + * - method taken from editview.c - mouse_cursor() + */ + project_short_noclip(ar, fp, mval); + window_to_3d(ar, dvec, mval[0]-mx, mval[1]-my); + VecSubf(p3d, fp, dvec); + } +} + +/* --- */ + +/* convert stroke to 3d path */ +static void gp_stroke_to_path (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu) +{ + bGPDspoint *pt; + Nurb *nu; + BPoint *bp; + int i; + + /* create new 'nurb' within the curve */ + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); + + nu->pntsu= gps->totpoints; + nu->pntsv= 1; + nu->orderu= gps->totpoints; + nu->flagu= 2; /* endpoint */ + nu->resolu= 32; + + nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints"); + + /* add points */ + for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) { + float p3d[3]; + + /* get coordinates to add at */ + gp_strokepoint_convertcoords(C, gps, pt, p3d); + VecCopyf(bp->vec, p3d); + + /* set settings */ + bp->f1= SELECT; + bp->radius = bp->weight = pt->pressure * gpl->thickness; + } + + /* add nurb to curve */ + BLI_addtail(&cu->nurb, nu); +} + +/* convert stroke to 3d bezier */ +static void gp_stroke_to_bezier (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu) +{ + bGPDspoint *pt; + Nurb *nu; + BezTriple *bezt; + int i; + + /* create new 'nurb' within the curve */ + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); + + nu->pntsu= gps->totpoints; + nu->resolu= 12; + nu->resolv= 12; + nu->type= CU_BEZIER; + nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts"); + + /* add points */ + for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) { + float p3d[3]; + + /* get coordinates to add at */ + gp_strokepoint_convertcoords(C, gps, pt, p3d); + + /* TODO: maybe in future the handles shouldn't be in same place */ + VecCopyf(bezt->vec[0], p3d); + VecCopyf(bezt->vec[1], p3d); + VecCopyf(bezt->vec[2], p3d); + + /* set settings */ + bezt->h1= bezt->h2= HD_FREE; + bezt->f1= bezt->f2= bezt->f3= SELECT; + bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f; + } + + /* must calculate handles or else we crash */ + calchandlesNurb(nu); + + /* add nurb to curve */ + BLI_addtail(&cu->nurb, nu); +} + +/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */ +static void gp_layer_to_curve (bContext *C, bGPdata *gpd, bGPDlayer *gpl, short mode) +{ + Scene *scene= CTX_data_scene(C); + bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0); + bGPDstroke *gps; + Base *base= BASACT; + Object *ob; + Curve *cu; + + /* error checking */ + if (ELEM3(NULL, gpd, gpl, gpf)) + return; + + /* only convert if there are any strokes on this layer's frame to convert */ + if (gpf->strokes.first == NULL) + return; + + /* init the curve object (remove rotation and get curve data from it) + * - must clear transforms set on object, as those skew our results + */ + ob= add_object(scene, OB_CURVE); + ob->loc[0]= ob->loc[1]= ob->loc[2]= 0; + ob->rot[0]= ob->rot[1]= ob->rot[2]= 0; + cu= ob->data; + cu->flag |= CU_3D; + + /* rename object and curve to layer name */ + rename_id((ID *)ob, gpl->info); + rename_id((ID *)cu, gpl->info); + + /* add points to curve */ + for (gps= gpf->strokes.first; gps; gps= gps->next) { + switch (mode) { + case GP_STROKECONVERT_PATH: + gp_stroke_to_path(C, gpl, gps, cu); + break; + case GP_STROKECONVERT_CURVE: + gp_stroke_to_bezier(C, gpl, gps, cu); + break; + } + } + + /* restore old active object */ + BASACT= base; +} + +/* --- */ + +static int gp_convert_poll (bContext *C) +{ + bGPdata *gpd= gpencil_data_get_active(C); + ScrArea *sa= CTX_wm_area(C); + + /* only if there's valid data, and the current view is 3D View */ + return ((sa->spacetype == SPACE_VIEW3D) && gpencil_layer_getactive(gpd)); +} + +static int gp_convert_layer_exec (bContext *C, wmOperator *op) +{ + bGPdata *gpd= gpencil_data_get_active(C); + bGPDlayer *gpl= gpencil_layer_getactive(gpd); + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + float *fp= give_cursor(scene, v3d); + int mode= RNA_enum_get(op->ptr, "type"); + + /* check if there's data to work with */ + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on."); + return OPERATOR_CANCELLED; + } + + /* initialise 3d-cursor correction globals */ + initgrabz(CTX_wm_region_view3d(C), fp[0], fp[1], fp[2]); + + /* handle conversion modes */ + switch (mode) { + case GP_STROKECONVERT_PATH: + case GP_STROKECONVERT_CURVE: + gp_layer_to_curve(C, gpd, gpl, mode); + break; + + default: /* unsupoorted */ + BKE_report(op->reports, RPT_ERROR, "Unknown conversion option."); + return OPERATOR_CANCELLED; + } + + /* notifiers */ + WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_convert (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Convert Grease Pencil"; + ot->idname= "GPENCIL_OT_convert"; + ot->description= "Convert the active Grease Pencil layer to a new Object."; + + /* callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= gp_convert_layer_exec; + ot->poll= gp_convert_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", ""); +} + /* ************************************************ */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 2c7bf9156c3..57e8c882d20 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -54,6 +54,10 @@ void GPENCIL_OT_data_unlink(struct wmOperatorType *ot); void GPENCIL_OT_layer_add(struct wmOperatorType *ot); +void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); + +void GPENCIL_OT_convert(struct wmOperatorType *ot); + /******************************************************* */ /* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 3acbded0bf8..d33ad16dfb1 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -76,6 +76,10 @@ void ED_operatortypes_gpencil (void) WM_operatortype_append(GPENCIL_OT_layer_add); + WM_operatortype_append(GPENCIL_OT_active_frame_delete); + + WM_operatortype_append(GPENCIL_OT_convert); + /* Editing (Time) --------------- */ } -- cgit v1.2.3