|
Blender
V2.59
|
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 /* ************************************************ */