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