rename operators TFM_OT_* --> TRANSFORM_OT_*
[blender.git] / source / blender / editors / gpencil / gpencil_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <math.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "IMB_imbuf.h"
38 #include "IMB_imbuf_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_blenlib.h"
42
43 #include "DNA_listBase.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_curve_types.h"
46 #include "DNA_gpencil_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_node_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_userdef_types.h"
53 #include "DNA_vec_types.h"
54 #include "DNA_view3d_types.h"
55
56 #include "BKE_armature.h"
57 #include "BKE_blender.h"
58 #include "BKE_context.h"
59 #include "BKE_curve.h"
60 #include "BKE_global.h"
61 #include "BKE_gpencil.h"
62 #include "BKE_image.h"
63 #include "BKE_library.h"
64 #include "BKE_object.h"
65 #include "BKE_report.h"
66 #include "BKE_utildefines.h"
67
68 #include "BIF_gl.h"
69 #include "BIF_glutil.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76
77 #include "UI_view2d.h"
78
79 #include "ED_armature.h"
80 #include "ED_gpencil.h"
81 #include "ED_sequencer.h"
82 #include "ED_view3d.h"
83
84 #include "gpencil_intern.h"
85
86 /* ************************************************ */
87 /* Context Wrangling... */
88
89 /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
90 bGPdata **gpencil_data_get_pointers (bContext *C, PointerRNA *ptr)
91 {
92         Scene *scene= CTX_data_scene(C);
93         ScrArea *sa= CTX_wm_area(C);
94         
95         /* if there's an active area, check if the particular editor may
96          * have defined any special Grease Pencil context for editing...
97          */
98         if (sa) {
99                 switch (sa->spacetype) {
100                         case SPACE_VIEW3D: /* 3D-View */
101                         {
102                                 Object *ob= CTX_data_active_object(C);
103                                 
104                                 // TODO: we can include other data-types such as bones later if need be...
105                                 
106                                 /* just in case no active object */
107                                 if (ob) {
108                                         /* for now, as long as there's an object, default to using that in 3D-View */
109                                         if (ptr) RNA_id_pointer_create(&ob->id, ptr);
110                                         return &ob->gpd;
111                                 }
112                         }
113                                 break;
114                         
115                         case SPACE_NODE: /* Nodes Editor */
116                         {
117                                 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
118                                 
119                                 /* return the GP data for the active node block/node */
120                                 if (snode && snode->nodetree) {
121                                         /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
122                                         if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
123                                         return &snode->nodetree->gpd;
124                                 }
125                                 else {
126                                         /* even when there is no node-tree, don't allow this to flow to scene */
127                                         return NULL;
128                                 }
129                         }
130                                 break;
131                                 
132                         case SPACE_SEQ: /* Sequencer */
133                         {
134                                 //SpaceSeq *sseq= (SpaceSeq *)CTX_wm_space_data(C);
135                                 
136                                 /* return the GP data for the active strips/image/etc. */
137                         }
138                                 break;
139                                 
140                         case SPACE_IMAGE: /* Image/UV Editor */
141                         {
142                                 SpaceImage *sima= (SpaceImage *)CTX_wm_space_data(C);
143                                 
144                                 /* for now, Grease Pencil data is associated with the space... */
145                                 // XXX our convention for everything else is to link to data though...
146                                 if (ptr) RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_SpaceImageEditor, sima, ptr);
147                                 return &sima->gpd;
148                         }
149                                 break;
150                                 
151                         default: /* unsupported space */
152                                 return NULL;
153                 }
154         }
155         
156         /* just fall back on the scene's GP data */
157         if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
158         return (scene) ? &scene->gpd : NULL;
159 }
160
161 /* Get the active Grease Pencil datablock */
162 bGPdata *gpencil_data_get_active (bContext *C)
163 {
164         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
165         return (gpd_ptr) ? *(gpd_ptr) : NULL;
166 }
167
168 /* needed for offscreen rendering */
169 bGPdata *gpencil_data_get_active_v3d (Scene *scene)
170 {
171         bGPdata *gpd= scene->basact ? scene->basact->object->gpd : NULL;
172         return gpd ? gpd : scene->gpd;
173 }
174
175 /* ************************************************ */
176 /* Panel Operators */
177
178 /* poll callback for adding data/layers - special */
179 static int gp_add_poll (bContext *C)
180 {
181         /* the base line we have is that we have somewhere to add Grease Pencil data */
182         return gpencil_data_get_pointers(C, NULL) != NULL;
183 }
184
185 /* ******************* Add New Data ************************ */
186
187 /* add new datablock - wrapper around API */
188 static int gp_data_add_exec (bContext *C, wmOperator *op)
189 {
190         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
191         
192         if (gpd_ptr == NULL) {
193                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
194                 return OPERATOR_CANCELLED;
195         }
196         else {
197                 /* just add new datablock now */
198                 *gpd_ptr= gpencil_data_addnew("GPencil");
199         }
200         
201         /* notifiers */
202         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work  
203         
204         return OPERATOR_FINISHED;
205 }
206
207 void GPENCIL_OT_data_add (wmOperatorType *ot)
208 {
209         /* identifiers */
210         ot->name= "Grease Pencil Add New";
211         ot->idname= "GPENCIL_OT_data_add";
212         ot->description= "Add new Grease Pencil datablock.";
213         
214         /* callbacks */
215         ot->exec= gp_data_add_exec;
216         ot->poll= gp_add_poll;
217 }
218
219 /* ******************* Unlink Data ************************ */
220
221 /* poll callback for adding data/layers - special */
222 static int gp_data_unlink_poll (bContext *C)
223 {
224         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
225         
226         /* if we have access to some active data, make sure there's a datablock before enabling this */
227         return (gpd_ptr && *gpd_ptr);
228 }
229
230
231 /* unlink datablock - wrapper around API */
232 static int gp_data_unlink_exec (bContext *C, wmOperator *op)
233 {
234         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
235         
236         if (gpd_ptr == NULL) {
237                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
238                 return OPERATOR_CANCELLED;
239         }
240         else {
241                 /* just unlink datablock now, decreasing its user count */
242                 bGPdata *gpd= (*gpd_ptr);
243                 
244                 gpd->id.us--;
245                 *gpd_ptr= NULL;
246         }
247         
248         /* notifiers */
249         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work  
250         
251         return OPERATOR_FINISHED;
252 }
253
254 void GPENCIL_OT_data_unlink (wmOperatorType *ot)
255 {
256         /* identifiers */
257         ot->name= "Grease Pencil Unlink";
258         ot->idname= "GPENCIL_OT_data_unlink";
259         ot->description= "Unlink active Grease Pencil datablock.";
260         
261         /* callbacks */
262         ot->exec= gp_data_unlink_exec;
263         ot->poll= gp_data_unlink_poll;
264 }
265
266 /* ******************* Add New Layer ************************ */
267
268 /* add new layer - wrapper around API */
269 static int gp_layer_add_exec (bContext *C, wmOperator *op)
270 {
271         bGPdata **gpd_ptr= gpencil_data_get_pointers(C, NULL);
272         
273         /* if there's no existing Grease-Pencil data there, add some */
274         if (gpd_ptr == NULL) {
275                 BKE_report(op->reports, RPT_ERROR, "Nowhere for Grease Pencil data to go");
276                 return OPERATOR_CANCELLED;
277         }
278         if (*gpd_ptr == NULL)
279                 *gpd_ptr= gpencil_data_addnew("GPencil");
280                 
281         /* add new layer now */
282         gpencil_layer_addnew(*gpd_ptr);
283         
284         /* notifiers */
285         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX please work!
286         
287         return OPERATOR_FINISHED;
288 }
289
290 void GPENCIL_OT_layer_add (wmOperatorType *ot)
291 {
292         /* identifiers */
293         ot->name= "Add New Layer";
294         ot->idname= "GPENCIL_OT_layer_add";
295         ot->description= "Add new Grease Pencil layer for the active Grease Pencil datablock.";
296         
297         /* callbacks */
298         ot->exec= gp_layer_add_exec;
299         ot->poll= gp_add_poll;
300 }
301
302 /* ******************* Delete Active Frame ************************ */
303
304 static int gp_actframe_delete_poll (bContext *C)
305 {
306         bGPdata *gpd= gpencil_data_get_active(C);
307         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
308         
309         /* only if there's an active layer with an active frame */
310         return (gpl && gpl->actframe);
311 }
312
313 /* delete active frame - wrapper around API calls */
314 static int gp_actframe_delete_exec (bContext *C, wmOperator *op)
315 {
316         Scene *scene= CTX_data_scene(C);
317         bGPdata *gpd= gpencil_data_get_active(C);
318         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
319         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
320         
321         /* if there's no existing Grease-Pencil data there, add some */
322         if (gpd == NULL) {
323                 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
324                 return OPERATOR_CANCELLED;
325         }
326         if ELEM(NULL, gpl, gpf) {
327                 BKE_report(op->reports, RPT_ERROR, "No active frame to delete");
328                 return OPERATOR_CANCELLED;
329         }
330         
331         /* delete it... */
332         gpencil_layer_delframe(gpl, gpf);
333         
334         /* notifiers */
335         WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX please work!
336         
337         return OPERATOR_FINISHED;
338 }
339
340 void GPENCIL_OT_active_frame_delete (wmOperatorType *ot)
341 {
342         /* identifiers */
343         ot->name= "Delete Active Frame";
344         ot->idname= "GPENCIL_OT_active_frame_delete";
345         ot->description= "Delete the active frame for the active Grease Pencil datablock.";
346         
347         /* callbacks */
348         ot->exec= gp_actframe_delete_exec;
349         ot->poll= gp_actframe_delete_poll;
350 }
351
352 /* ************************************************ */
353 /* Grease Pencil to Data Operator */
354
355 /* defines for possible modes */
356 enum {
357         GP_STROKECONVERT_PATH = 1,
358         GP_STROKECONVERT_CURVE,
359 };
360
361 /* RNA enum define */
362 static EnumPropertyItem prop_gpencil_convertmodes[] = {
363         {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
364         {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
365         {0, NULL, 0, NULL, NULL}
366 };
367
368 /* --- */
369
370 /* convert the coordinates from the given stroke point into 3d-coordinates 
371  *      - assumes that the active space is the 3D-View
372  */
373 static void gp_strokepoint_convertcoords (bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3])
374 {
375         Scene *scene= CTX_data_scene(C);
376         View3D *v3d= CTX_wm_view3d(C);
377         ARegion *ar= CTX_wm_region(C);
378         
379         if (gps->flag & GP_STROKE_3DSPACE) {
380                 /* directly use 3d-coordinates */
381                 copy_v3_v3(p3d, &pt->x);
382         }
383         else {
384                 float *fp= give_cursor(scene, v3d);
385                 float dvec[3];
386                 short mval[2];
387                 int mx, my;
388                 
389                 /* get screen coordinate */
390                 if (gps->flag & GP_STROKE_2DSPACE) {
391                         View2D *v2d= &ar->v2d;
392                         UI_view2d_view_to_region(v2d, pt->x, pt->y, &mx, &my);
393                 }
394                 else {
395                         mx= (int)(pt->x / 100 * ar->winx);
396                         my= (int)(pt->y / 100 * ar->winy);
397                 }
398                 mval[0]= (short)mx;
399                 mval[1]= (short)my;
400                 
401                 /* convert screen coordinate to 3d coordinates 
402                  *      - method taken from editview.c - mouse_cursor() 
403                  */
404                 project_short_noclip(ar, fp, mval);
405                 window_to_3d(ar, dvec, mval[0]-mx, mval[1]-my);
406                 sub_v3_v3v3(p3d, fp, dvec);
407         }
408 }
409
410 /* --- */
411
412 /* convert stroke to 3d path */
413 static void gp_stroke_to_path (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
414 {
415         bGPDspoint *pt;
416         Nurb *nu;
417         BPoint *bp;
418         int i;
419         
420         /* create new 'nurb' within the curve */
421         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
422         
423         nu->pntsu= gps->totpoints;
424         nu->pntsv= 1;
425         nu->orderu= gps->totpoints;
426         nu->flagu= 2;   /* endpoint */
427         nu->resolu= 32;
428         
429         nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
430         
431         /* add points */
432         for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
433                 float p3d[3];
434                 
435                 /* get coordinates to add at */
436                 gp_strokepoint_convertcoords(C, gps, pt, p3d);
437                 copy_v3_v3(bp->vec, p3d);
438                 
439                 /* set settings */
440                 bp->f1= SELECT;
441                 bp->radius = bp->weight = pt->pressure * gpl->thickness;
442         }
443         
444         /* add nurb to curve */
445         BLI_addtail(&cu->nurb, nu);
446 }
447
448 /* convert stroke to 3d bezier */
449 static void gp_stroke_to_bezier (bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
450 {
451         bGPDspoint *pt;
452         Nurb *nu;
453         BezTriple *bezt;
454         int i;
455         
456         /* create new 'nurb' within the curve */
457         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
458         
459         nu->pntsu= gps->totpoints;
460         nu->resolu= 12;
461         nu->resolv= 12;
462         nu->type= CU_BEZIER;
463         nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
464         
465         /* add points */
466         for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) {
467                 float p3d[3];
468                 
469                 /* get coordinates to add at */
470                 gp_strokepoint_convertcoords(C, gps, pt, p3d);
471                 
472                 /* TODO: maybe in future the handles shouldn't be in same place */
473                 copy_v3_v3(bezt->vec[0], p3d);
474                 copy_v3_v3(bezt->vec[1], p3d);
475                 copy_v3_v3(bezt->vec[2], p3d);
476                 
477                 /* set settings */
478                 bezt->h1= bezt->h2= HD_FREE;
479                 bezt->f1= bezt->f2= bezt->f3= SELECT;
480                 bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f;
481         }
482         
483         /* must calculate handles or else we crash */
484         calchandlesNurb(nu);
485         
486         /* add nurb to curve */
487         BLI_addtail(&cu->nurb, nu);
488 }
489
490 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
491 static void gp_layer_to_curve (bContext *C, bGPdata *gpd, bGPDlayer *gpl, short mode)
492 {
493         Scene *scene= CTX_data_scene(C);
494         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
495         bGPDstroke *gps;
496         Object *ob;
497         Curve *cu;
498         
499         /* error checking */
500         if (ELEM3(NULL, gpd, gpl, gpf))
501                 return;
502                 
503         /* only convert if there are any strokes on this layer's frame to convert */
504         if (gpf->strokes.first == NULL)
505                 return;
506         
507         /* init the curve object (remove rotation and get curve data from it)
508          *      - must clear transforms set on object, as those skew our results
509          */
510         ob= add_object(scene, OB_CURVE);
511         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
512         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
513         cu= ob->data;
514         cu->flag |= CU_3D;
515         
516         /* rename object and curve to layer name */
517         rename_id((ID *)ob, gpl->info);
518         rename_id((ID *)cu, gpl->info);
519         
520         /* add points to curve */
521         for (gps= gpf->strokes.first; gps; gps= gps->next) {
522                 switch (mode) {
523                         case GP_STROKECONVERT_PATH: 
524                                 gp_stroke_to_path(C, gpl, gps, cu);
525                                 break;
526                         case GP_STROKECONVERT_CURVE:
527                                 gp_stroke_to_bezier(C, gpl, gps, cu);
528                                 break;
529                 }
530         }
531 }
532
533 /* --- */
534
535 static int gp_convert_poll (bContext *C)
536 {
537         bGPdata *gpd= gpencil_data_get_active(C);
538         ScrArea *sa= CTX_wm_area(C);
539         
540         /* only if there's valid data, and the current view is 3D View */
541         return ((sa->spacetype == SPACE_VIEW3D) && gpencil_layer_getactive(gpd));
542 }
543
544 static int gp_convert_layer_exec (bContext *C, wmOperator *op)
545 {
546         bGPdata *gpd= gpencil_data_get_active(C);
547         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
548         Scene *scene= CTX_data_scene(C);
549         View3D *v3d= CTX_wm_view3d(C);
550         float *fp= give_cursor(scene, v3d);
551         int mode= RNA_enum_get(op->ptr, "type");
552         
553         /* check if there's data to work with */
554         if (gpd == NULL) {
555                 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on.");
556                 return OPERATOR_CANCELLED;
557         }
558         
559         /* initialise 3d-cursor correction globals */
560         initgrabz(CTX_wm_region_view3d(C), fp[0], fp[1], fp[2]);
561         
562         /* handle conversion modes */
563         switch (mode) {
564                 case GP_STROKECONVERT_PATH:
565                 case GP_STROKECONVERT_CURVE:
566                         gp_layer_to_curve(C, gpd, gpl, mode);
567                         break;
568                         
569                 default: /* unsupoorted */
570                         BKE_report(op->reports, RPT_ERROR, "Unknown conversion option.");
571                         return OPERATOR_CANCELLED;
572         }
573                 
574         /* notifiers */
575         WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, NULL);
576         
577         /* done */
578         return OPERATOR_FINISHED;
579 }
580
581 void GPENCIL_OT_convert (wmOperatorType *ot)
582 {
583         /* identifiers */
584         ot->name= "Convert Grease Pencil";
585         ot->idname= "GPENCIL_OT_convert";
586         ot->description= "Convert the active Grease Pencil layer to a new Object.";
587         
588         /* callbacks */
589         ot->invoke= WM_menu_invoke;
590         ot->exec= gp_convert_layer_exec;
591         ot->poll= gp_convert_poll;
592         
593         /* flags */
594         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
595         
596         /* properties */
597         RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "");
598 }
599
600 /* ************************************************ */