Blender  V2.59
gpencil_edit.c
Go to the documentation of this file.
00001 /*
00002  * $Id: gpencil_edit.c 36966 2011-05-28 04:53:17Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
00021  * This is a new part of Blender
00022  *
00023  * Contributor(s): Joshua Leung
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <stddef.h>
00038 #include <math.h>
00039 
00040 #include "MEM_guardedalloc.h"
00041 
00042 
00043 #include "BLI_math.h"
00044 #include "BLI_blenlib.h"
00045 #include "BLI_utildefines.h"
00046 
00047 #include "DNA_curve_types.h"
00048 #include "DNA_object_types.h"
00049 #include "DNA_node_types.h"
00050 #include "DNA_scene_types.h"
00051 #include "DNA_screen_types.h"
00052 #include "DNA_space_types.h"
00053 #include "DNA_view3d_types.h"
00054 #include "DNA_gpencil_types.h"
00055 
00056 #include "BKE_context.h"
00057 #include "BKE_curve.h"
00058 #include "BKE_gpencil.h"
00059 #include "BKE_library.h"
00060 #include "BKE_object.h"
00061 #include "BKE_report.h"
00062 
00063 
00064 #include "WM_api.h"
00065 #include "WM_types.h"
00066 
00067 #include "RNA_access.h"
00068 #include "RNA_define.h"
00069 
00070 #include "UI_view2d.h"
00071 
00072 #include "ED_gpencil.h"
00073 #include "ED_view3d.h"
00074 
00075 #include "gpencil_intern.h"
00076 
00077 /* ************************************************ */
00078 /* Context Wrangling... */
00079 
00080 /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
00081 bGPdata **gpencil_data_get_pointers (bContext *C, PointerRNA *ptr)
00082 {
00083         Scene *scene= CTX_data_scene(C);
00084         ScrArea *sa= CTX_wm_area(C);
00085         
00086         /* if there's an active area, check if the particular editor may
00087          * have defined any special Grease Pencil context for editing...
00088          */
00089         if (sa) {
00090                 switch (sa->spacetype) {
00091                         case SPACE_VIEW3D: /* 3D-View */
00092                         {
00093                                 Object *ob= CTX_data_active_object(C);
00094                                 
00095                                 // TODO: we can include other data-types such as bones later if need be...
00096                                 
00097                                 /* just in case no active object */
00098                                 if (ob) {
00099                                         /* for now, as long as there's an object, default to using that in 3D-View */
00100                                         if (ptr) RNA_id_pointer_create(&ob->id, ptr);
00101                                         return &ob->gpd;
00102                                 }
00103                         }
00104                                 break;
00105                         
00106                         case SPACE_NODE: /* Nodes Editor */
00107                         {
00108                                 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
00109                                 
00110                                 /* return the GP data for the active node block/node */
00111                                 if (snode && snode->nodetree) {
00112                                         /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
00113                                         if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
00114                                         return &snode->nodetree->gpd;
00115                                 }
00116                                 else {
00117                                         /* even when there is no node-tree, don't allow this to flow to scene */
00118                                         return NULL;
00119                                 }
00120                         }
00121                                 break;
00122                                 
00123                         case SPACE_SEQ: /* Sequencer */
00124                         {
00125                                 //SpaceSeq *sseq= (SpaceSeq *)CTX_wm_space_data(C);
00126                                 
00127                                 /* return the GP data for the active strips/image/etc. */
00128                         }
00129                                 break;
00130                                 
00131                         case SPACE_IMAGE: /* Image/UV Editor */
00132                         {
00133                                 SpaceImage *sima= (SpaceImage *)CTX_wm_space_data(C);
00134                                 
00135                                 /* for now, Grease Pencil data is associated with the space... */
00136                                 // XXX our convention for everything else is to link to data though...
00137                                 if (ptr) RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_SpaceImageEditor, sima, ptr);
00138                                 return &sima->gpd;
00139                         }
00140                                 break;
00141                                 
00142                         default: /* unsupported space */
00143                                 return NULL;
00144                 }
00145         }
00146         
00147         /* just fall back on the scene's GP data */
00148         if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
00149         return (scene) ? &scene->gpd : NULL;
00150 }
00151 
00152 /* Get the active Grease Pencil datablock */
00153 bGPdata *gpencil_data_get_active (bContext *C)
00154 {
00155         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
00156         return (gpd_ptr) ? *(gpd_ptr) : NULL;
00157 }
00158 
00159 /* needed for offscreen rendering */
00160 bGPdata *gpencil_data_get_active_v3d (Scene *scene)
00161 {
00162         bGPdata *gpd= scene->basact ? scene->basact->object->gpd : NULL;
00163         return gpd ? gpd : scene->gpd;
00164 }
00165 
00166 /* ************************************************ */
00167 /* Panel Operators */
00168 
00169 /* poll callback for adding data/layers - special */
00170 static int gp_add_poll (bContext *C)
00171 {
00172         /* the base line we have is that we have somewhere to add Grease Pencil data */
00173         return gpencil_data_get_pointers(C, NULL) != NULL;
00174 }
00175 
00176 /* ******************* Add New Data ************************ */
00177 
00178 /* add new datablock - wrapper around API */
00179 static int gp_data_add_exec (bContext *C, wmOperator *op)
00180 {
00181         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
00182         
00183         if (gpd_ptr == NULL) {
00184                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
00185                 return OPERATOR_CANCELLED;
00186         }
00187         else {
00188                 /* just add new datablock now */
00189                 *gpd_ptr= gpencil_data_addnew("GPencil");
00190         }
00191         
00192         /* notifiers */
00193         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work  
00194         
00195         return OPERATOR_FINISHED;
00196 }
00197 
00198 void GPENCIL_OT_data_add (wmOperatorType *ot)
00199 {
00200         /* identifiers */
00201         ot->name= "Grease Pencil Add New";
00202         ot->idname= "GPENCIL_OT_data_add";
00203         ot->description= "Add new Grease Pencil datablock";
00204         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00205         
00206         /* callbacks */
00207         ot->exec= gp_data_add_exec;
00208         ot->poll= gp_add_poll;
00209 }
00210 
00211 /* ******************* Unlink Data ************************ */
00212 
00213 /* poll callback for adding data/layers - special */
00214 static int gp_data_unlink_poll (bContext *C)
00215 {
00216         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
00217         
00218         /* if we have access to some active data, make sure there's a datablock before enabling this */
00219         return (gpd_ptr && *gpd_ptr);
00220 }
00221 
00222 
00223 /* unlink datablock - wrapper around API */
00224 static int gp_data_unlink_exec (bContext *C, wmOperator *op)
00225 {
00226         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
00227         
00228         if (gpd_ptr == NULL) {
00229                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
00230                 return OPERATOR_CANCELLED;
00231         }
00232         else {
00233                 /* just unlink datablock now, decreasing its user count */
00234                 bGPdata *gpd= (*gpd_ptr);
00235                 
00236                 gpd->id.us--;
00237                 *gpd_ptr= NULL;
00238         }
00239         
00240         /* notifiers */
00241         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work  
00242         
00243         return OPERATOR_FINISHED;
00244 }
00245 
00246 void GPENCIL_OT_data_unlink (wmOperatorType *ot)
00247 {
00248         /* identifiers */
00249         ot->name= "Grease Pencil Unlink";
00250         ot->idname= "GPENCIL_OT_data_unlink";
00251         ot->description= "Unlink active Grease Pencil datablock";
00252         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00253         
00254         /* callbacks */
00255         ot->exec= gp_data_unlink_exec;
00256         ot->poll= gp_data_unlink_poll;
00257 }
00258 
00259 /* ******************* Add New Layer ************************ */
00260 
00261 /* add new layer - wrapper around API */
00262 static int gp_layer_add_exec (bContext *C, wmOperator *op)
00263 {
00264         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
00265         
00266         /* if there's no existing Grease-Pencil data there, add some */
00267         if (gpd_ptr == NULL) {
00268                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
00269                 return OPERATOR_CANCELLED;
00270         }
00271         if (*gpd_ptr == NULL)
00272                 *gpd_ptr= gpencil_data_addnew("GPencil");
00273                 
00274         /* add new layer now */
00275         gpencil_layer_addnew(*gpd_ptr);
00276         
00277         /* notifiers */
00278         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX please work!
00279         
00280         return OPERATOR_FINISHED;
00281 }
00282 
00283 void GPENCIL_OT_layer_add (wmOperatorType *ot)
00284 {
00285         /* identifiers */
00286         ot->name= "Add New Layer";
00287         ot->idname= "GPENCIL_OT_layer_add";
00288         ot->description= "Add new Grease Pencil layer for the active Grease Pencil datablock";
00289         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00290         
00291         /* callbacks */
00292         ot->exec= gp_layer_add_exec;
00293         ot->poll= gp_add_poll;
00294 }
00295 
00296 /* ******************* Delete Active Frame ************************ */
00297 
00298 static int gp_actframe_delete_poll (bContext *C)
00299 {
00300         bGPdata *gpd= gpencil_data_get_active(C);
00301         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
00302         
00303         /* only if there's an active layer with an active frame */
00304         return (gpl && gpl->actframe);
00305 }
00306 
00307 /* delete active frame - wrapper around API calls */
00308 static int gp_actframe_delete_exec (bContext *C, wmOperator *op)
00309 {
00310         Scene *scene= CTX_data_scene(C);
00311         bGPdata *gpd= gpencil_data_get_active(C);
00312         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
00313         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
00314         
00315         /* if there's no existing Grease-Pencil data there, add some */
00316         if (gpd == NULL) {
00317                 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
00318                 return OPERATOR_CANCELLED;
00319         }
00320         if ELEM(NULL, gpl, gpf) {
00321                 BKE_report(op->reports, RPT_ERROR, "No active frame to delete");
00322                 return OPERATOR_CANCELLED;
00323         }
00324         
00325         /* delete it... */
00326         gpencil_layer_delframe(gpl, gpf);
00327         
00328         /* notifiers */
00329         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX please work!
00330         
00331         return OPERATOR_FINISHED;
00332 }
00333 
00334 void GPENCIL_OT_active_frame_delete (wmOperatorType *ot)
00335 {
00336         /* identifiers */
00337         ot->name= "Delete Active Frame";
00338         ot->idname= "GPENCIL_OT_active_frame_delete";
00339         ot->description= "Delete the active frame for the active Grease Pencil datablock";
00340         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00341         
00342         /* callbacks */
00343         ot->exec= gp_actframe_delete_exec;
00344         ot->poll= gp_actframe_delete_poll;
00345 }
00346 
00347 /* ************************************************ */
00348 /* Grease Pencil to Data Operator */
00349 
00350 /* defines for possible modes */
00351 enum {
00352         GP_STROKECONVERT_PATH = 1,
00353         GP_STROKECONVERT_CURVE,
00354 };
00355 
00356 /* RNA enum define */
00357 static EnumPropertyItem prop_gpencil_convertmodes[] = {
00358         {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
00359         {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
00360         {0, NULL, 0, NULL, NULL}
00361 };
00362 
00363 /* --- */
00364 
00365 /* convert the coordinates from the given stroke point into 3d-coordinates 
00366  *      - assumes that the active space is the 3D-View
00367  */
00368 static void gp_strokepoint_convertcoords (bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
00369 {
00370         Scene *scene= CTX_data_scene(C);
00371         View3D *v3d= CTX_wm_view3d(C);
00372         ARegion *ar= CTX_wm_region(C);
00373         
00374         if (gps->flag & GP_STROKE_3DSPACE) {
00375                 /* directly use 3d-coordinates */
00376                 copy_v3_v3(p3d, &pt->x);
00377         }
00378         else {
00379                 float *fp= give_cursor(scene, v3d);
00380                 float mvalf[2];
00381                 
00382                 /* get screen coordinate */
00383                 if (gps->flag & GP_STROKE_2DSPACE) {
00384                         int mvali[2];
00385                         View2D *v2d= &ar->v2d;
00386                         UI_view2d_view_to_region(v2d, pt->x, pt->y, mvali, mvali+1);
00387                         VECCOPY2D(mvalf, mvali);
00388                 }
00389                 else {
00390                         if(subrect) {
00391                                 mvalf[0]= (((float)pt->x/100.0f) * (subrect->xmax - subrect->xmin)) + subrect->xmin;
00392                                 mvalf[1]= (((float)pt->y/100.0f) * (subrect->ymax - subrect->ymin)) + subrect->ymin;
00393                         }
00394                         else {
00395                                 mvalf[0]= (float)pt->x / 100.0f * ar->winx;
00396                                 mvalf[1]= (float)pt->y / 100.0f * ar->winy;
00397                         }
00398                 }
00399 
00400                 /* convert screen coordinate to 3d coordinates 
00401                  *      - method taken from editview.c - mouse_cursor() 
00402                  */
00403                 ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
00404         }
00405 }
00406 
00407 /* --- */
00408 
00409 /* convert stroke to 3d path */
00410 static void gp_stroke_to_path (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect)
00411 {
00412         bGPDspoint *pt;
00413         Nurb *nu;
00414         BPoint *bp;
00415         int i;
00416 
00417         /* create new 'nurb' within the curve */
00418         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
00419         
00420         nu->pntsu= gps->totpoints;
00421         nu->pntsv= 1;
00422         nu->orderu= gps->totpoints;
00423         nu->flagu= CU_NURB_ENDPOINT;
00424         nu->resolu= 32;
00425         
00426         nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
00427         
00428         /* add points */
00429         for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
00430                 float p3d[3];
00431                 
00432                 /* get coordinates to add at */
00433                 gp_strokepoint_convertcoords(C, gps, pt, p3d, subrect);
00434                 copy_v3_v3(bp->vec, p3d);
00435                 
00436                 /* set settings */
00437                 bp->f1= SELECT;
00438                 bp->radius = bp->weight = pt->pressure * gpl->thickness;
00439         }
00440         
00441         /* add nurb to curve */
00442         BLI_addtail(&cu->nurb, nu);
00443 }
00444 
00445 static int gp_camera_view_subrect(bContext *C, rctf *subrect)
00446 {
00447         View3D *v3d= CTX_wm_view3d(C);
00448         ARegion *ar= CTX_wm_region(C);
00449 
00450         if (v3d) {
00451                 RegionView3D *rv3d= ar->regiondata;
00452 
00453                 /* for camera view set the subrect */
00454                 if (rv3d->persp == RV3D_CAMOB) {
00455                         Scene *scene= CTX_data_scene(C);
00456                         ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, -1); /* negative shift */
00457                         return 1;
00458                 }
00459         }
00460 
00461         return 0;
00462 }
00463 
00464 /* convert stroke to 3d bezier */
00465 static void gp_stroke_to_bezier (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect)
00466 {
00467         bGPDspoint *pt;
00468         Nurb *nu;
00469         BezTriple *bezt;
00470         int i, tot;
00471         float p3d_cur[3], p3d_prev[3], p3d_next[3];
00472 
00473         /* create new 'nurb' within the curve */
00474         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
00475 
00476         nu->pntsu= gps->totpoints;
00477         nu->resolu= 12;
00478         nu->resolv= 12;
00479         nu->type= CU_BEZIER;
00480         nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
00481 
00482         tot= gps->totpoints;
00483 
00484         /* get initial coordinates */
00485         pt=gps->points;
00486         if (tot) {
00487                 gp_strokepoint_convertcoords(C, gps, pt, p3d_cur, subrect);
00488                 if (tot > 1) {
00489                         gp_strokepoint_convertcoords(C, gps, pt+1, p3d_next, subrect);
00490                 }
00491         }
00492 
00493         /* add points */
00494         for (i=0, bezt=nu->bezt; i < tot; i++, pt++, bezt++) {
00495                 float h1[3], h2[3];
00496 
00497                 if (i) interp_v3_v3v3(h1, p3d_cur, p3d_prev, 0.3);
00498                 else interp_v3_v3v3(h1, p3d_cur, p3d_next, -0.3);
00499 
00500                 if (i < tot-1) interp_v3_v3v3(h2, p3d_cur, p3d_next, 0.3);
00501                 else interp_v3_v3v3(h2, p3d_cur, p3d_prev, -0.3);
00502 
00503                 copy_v3_v3(bezt->vec[0], h1);
00504                 copy_v3_v3(bezt->vec[1], p3d_cur);
00505                 copy_v3_v3(bezt->vec[2], h2);
00506 
00507                 /* set settings */
00508                 bezt->h1= bezt->h2= HD_FREE;
00509                 bezt->f1= bezt->f2= bezt->f3= SELECT;
00510                 bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f;
00511 
00512                 /* shift coord vects */
00513                 copy_v3_v3(p3d_prev, p3d_cur);
00514                 copy_v3_v3(p3d_cur, p3d_next);
00515 
00516                 if (i + 1 < tot) {
00517                         gp_strokepoint_convertcoords(C, gps, pt+1, p3d_next, subrect);
00518                 }
00519         }
00520 
00521         /* must calculate handles or else we crash */
00522         calchandlesNurb(nu);
00523 
00524         /* add nurb to curve */
00525         BLI_addtail(&cu->nurb, nu);
00526 }
00527 
00528 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
00529 static void gp_layer_to_curve (bContext *C, bGPdata *gpd, bGPDlayer *gpl, short mode)
00530 {
00531         Scene *scene= CTX_data_scene(C);
00532         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
00533         bGPDstroke *gps;
00534         Object *ob;
00535         Curve *cu;
00536 
00537         /* camera framing */
00538         rctf subrect, *subrect_ptr= NULL;
00539 
00540         /* error checking */
00541         if (ELEM3(NULL, gpd, gpl, gpf))
00542                 return;
00543                 
00544         /* only convert if there are any strokes on this layer's frame to convert */
00545         if (gpf->strokes.first == NULL)
00546                 return;
00547 
00548         /* initialize camera framing */
00549         if(gp_camera_view_subrect(C, &subrect)) {
00550                 subrect_ptr= &subrect;
00551         }
00552 
00553         /* init the curve object (remove rotation and get curve data from it)
00554          *      - must clear transforms set on object, as those skew our results
00555          */
00556         ob= add_object(scene, OB_CURVE);
00557         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
00558         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
00559         cu= ob->data;
00560         cu->flag |= CU_3D;
00561         
00562         /* rename object and curve to layer name */
00563         rename_id((ID *)ob, gpl->info);
00564         rename_id((ID *)cu, gpl->info);
00565         
00566         /* add points to curve */
00567         for (gps= gpf->strokes.first; gps; gps= gps->next) {
00568                 switch (mode) {
00569                         case GP_STROKECONVERT_PATH: 
00570                                 gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr);
00571                                 break;
00572                         case GP_STROKECONVERT_CURVE:
00573                                 gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr);
00574                                 break;
00575                 }
00576         }
00577 }
00578 
00579 /* --- */
00580 
00581 static int gp_convert_poll (bContext *C)
00582 {
00583         bGPdata *gpd= gpencil_data_get_active(C);
00584         ScrArea *sa= CTX_wm_area(C);
00585         Scene *scene= CTX_data_scene(C);
00586 
00587         /* only if there's valid data, and the current view is 3D View */
00588         return ((sa && sa->spacetype == SPACE_VIEW3D) && gpencil_layer_getactive(gpd) && (scene->obedit == NULL));
00589 }
00590 
00591 static int gp_convert_layer_exec (bContext *C, wmOperator *op)
00592 {
00593         bGPdata *gpd= gpencil_data_get_active(C);
00594         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
00595         Scene *scene= CTX_data_scene(C);
00596         int mode= RNA_enum_get(op->ptr, "type");
00597 
00598         /* check if there's data to work with */
00599         if (gpd == NULL) {
00600                 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on.");
00601                 return OPERATOR_CANCELLED;
00602         }
00603 
00604         /* handle conversion modes */
00605         switch (mode) {
00606                 case GP_STROKECONVERT_PATH:
00607                 case GP_STROKECONVERT_CURVE:
00608                         gp_layer_to_curve(C, gpd, gpl, mode);
00609                         break;
00610                         
00611                 default: /* unsupoorted */
00612                         BKE_report(op->reports, RPT_ERROR, "Unknown conversion option.");
00613                         return OPERATOR_CANCELLED;
00614         }
00615 
00616         /* notifiers */
00617         WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, NULL);
00618         WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00619 
00620         /* done */
00621         return OPERATOR_FINISHED;
00622 }
00623 
00624 void GPENCIL_OT_convert (wmOperatorType *ot)
00625 {
00626         /* identifiers */
00627         ot->name= "Convert Grease Pencil";
00628         ot->idname= "GPENCIL_OT_convert";
00629         ot->description= "Convert the active Grease Pencil layer to a new Object";
00630         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00631         
00632         /* callbacks */
00633         ot->invoke= WM_menu_invoke;
00634         ot->exec= gp_convert_layer_exec;
00635         ot->poll= gp_convert_poll;
00636         
00637         /* flags */
00638         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00639         
00640         /* properties */
00641         ot->prop= RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "");
00642 }
00643 
00644 /* ************************************************ */