Grease Pencil: Restored some editing operators (convert and delete active frame)
authorJoshua Leung <aligorith@gmail.com>
Mon, 31 Aug 2009 01:58:11 +0000 (01:58 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 31 Aug 2009 01:58:11 +0000 (01:58 +0000)
* 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
source/blender/editors/gpencil/gpencil_buttons.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/gpencil/gpencil_intern.h
source/blender/editors/gpencil/gpencil_ops.c

index b02128c3c68184922af1d4c4f27063739c3fe3dd..43c4137e73eab73ccaead4f3f3c957304e324f05 100644 (file)
@@ -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))
index 774f7b7162bc03726e49940fd871382e0a55c05b..c3f779b59b89780ee3c0efeb55f5cdc0e309ac0c 100644 (file)
@@ -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");
index 74fbe250d37ec4aabec55e7a6793ce12efbb6c87..8cf1affa8c6da9b149c2dcdeb9cc456e56f9f7f0 100644 (file)
@@ -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", "");
+}
+
 /* ************************************************ */
index 2c7bf9156c3ca683f3afc61a2b2c796486d6433f..57e8c882d20f920594145a633b31b38082f78545 100644 (file)
@@ -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! */
index 3acbded0bf81f0f517dc87f4dabde7c4d74d9db7..d33ad16dfb15b1f673d0e05044bb524bfcc1c09e 100644 (file)
@@ -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) --------------- */
 }