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