ed046929d2e1bc231827464b53844c2e74f46d6d
[blender.git] / source / blender / src / gpencil.c
1 /**
2  * $Id: gpencil.c 14881 2008-05-18 10:41:42Z aligorith $
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
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <math.h>
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BMF_Api.h"
41
42 #include "IMB_imbuf.h"
43 #include "IMB_imbuf_types.h"
44
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
47
48 #include "DNA_listBase.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_gpencil_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_userdef_types.h"
56 #include "DNA_vec_types.h"
57 #include "DNA_view3d_types.h"
58
59 #include "BKE_global.h"
60 #include "BKE_utildefines.h"
61 #include "BKE_blender.h"
62 #include "BKE_curve.h"
63
64 #include "BIF_gl.h"
65 #include "BIF_glutil.h"
66 #include "BIF_butspace.h"
67 #include "BIF_editview.h"
68 #include "BIF_graphics.h"
69 #include "BIF_interface.h"
70 #include "BIF_mywindow.h"
71 #include "BIF_resources.h"
72 #include "BIF_space.h"
73 #include "BIF_screen.h"
74 #include "BIF_toolbox.h"
75 #include "BIF_toets.h"
76
77 #include "BDR_gpencil.h"
78 #include "BIF_drawgpencil.h"
79
80 #include "BDR_editobject.h"
81
82 #include "BSE_drawipo.h"
83 #include "BSE_headerbuttons.h"
84 #include "BSE_view.h"
85
86 #include "blendef.h"
87
88 #include "PIL_time.h"                   /* sleep                                */
89 #include "mydevice.h"
90
91 /* ************************************************** */
92 /* GENERAL STUFF */
93
94 /* --------- Memory Management ------------ */
95
96 /* Free strokes belonging to a gp-frame */
97 void free_gpencil_strokes (bGPDframe *gpf)
98 {
99         bGPDstroke *gps, *gpsn;
100         
101         /* error checking */
102         if (gpf == NULL) return;
103         
104         /* free strokes */
105         for (gps= gpf->strokes.first; gps; gps= gpsn) {
106                 gpsn= gps->next;
107                 
108                 /* free stroke memory arrays, then stroke itself */
109                 MEM_freeN(gps->points);
110                 BLI_freelinkN(&gpf->strokes, gps);
111         }
112 }
113
114 /* Free all of a gp-layer's frames */
115 void free_gpencil_frames (bGPDlayer *gpl)
116 {
117         bGPDframe *gpf, *gpfn;
118         
119         /* error checking */
120         if (gpl == NULL) return;
121         
122         /* free frames */
123         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
124                 gpfn= gpf->next;
125                 
126                 /* free strokes and their associated memory */
127                 free_gpencil_strokes(gpf);
128                 BLI_freelinkN(&gpl->frames, gpf);
129         }
130 }
131
132 /* Free all of the gp-layers for a viewport (list should be &G.vd->gpd or so) */
133 void free_gpencil_layers (ListBase *list) 
134 {
135         bGPDlayer *gpl, *gpln;
136         
137         /* error checking */
138         if (list == NULL) return;
139         
140         /* delete layers*/
141         for (gpl= list->first; gpl; gpl= gpln) {
142                 gpln= gpl->next;
143                 
144                 /* free layers and their data */
145                 free_gpencil_frames(gpl);
146                 BLI_freelinkN(list, gpl);
147         }
148 }
149
150 /* Free gp-data and all it's related data */
151 void free_gpencil_data (bGPdata *gpd)
152 {
153         /* free layers then data itself */
154         free_gpencil_layers(&gpd->layers);
155         MEM_freeN(gpd);
156 }
157
158 /* -------- Container Creation ---------- */
159
160 /* add a new gp-frame to the given layer */
161 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
162 {
163         bGPDframe *gpf, *gf;
164         short state=0;
165         
166         /* error checking */
167         if ((gpl == NULL) || (cframe <= 0))
168                 return NULL;
169                 
170         /* allocate memory for this frame */
171         gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
172         gpf->framenum= cframe;
173         
174         /* find appropriate place to add frame */
175         if (gpl->frames.first) {
176                 for (gf= gpl->frames.first; gf; gf= gf->next) {
177                         /* check if frame matches one that is supposed to be added */
178                         if (gf->framenum == cframe) {
179                                 state= -1;
180                                 break;
181                         }
182                         
183                         /* if current frame has already exceeded the frame to add, add before */
184                         if (gf->framenum > cframe) {
185                                 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
186                                 state= 1;
187                                 break;
188                         }
189                 }
190         }
191         
192         /* check whether frame was added successfully */
193         if (state == -1) {
194                 MEM_freeN(gpf);
195                 printf("Error: frame (%d) existed already for this layer \n", cframe);
196         }
197         else if (state == 0) {
198                 /* add to end then! */
199                 BLI_addtail(&gpl->frames, gpf);
200         }
201         
202         /* return frame */
203         return gpf;
204 }
205
206 /* add a new gp-layer and make it the active layer */
207 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
208 {
209         bGPDlayer *gpl;
210         
211         /* check that list is ok */
212         if (gpd == NULL)
213                 return NULL;
214                 
215         /* allocate memory for frame and add to end of list */
216         gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
217         
218         /* add to datablock */
219         BLI_addtail(&gpd->layers, gpl);
220         
221         /* set basic settings */
222         gpl->color[3]= 1.0f;
223         gpl->thickness = 1;
224         
225         /* auto-name */
226         sprintf(gpl->info, "GP_Layer");
227         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
228         
229         /* make this one the active one */
230         gpencil_layer_setactive(gpd, gpl);
231         
232         /* return layer */
233         return gpl;
234 }
235
236 /* add a new gp-datablock */
237 bGPdata *gpencil_data_addnew (void)
238 {
239         bGPdata *gpd;
240         
241         /* allocate memory for a new block */
242         gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
243         
244         /* initial settings */
245                 /* it is quite useful to be able to see this info, so on by default */
246         gpd->flag = GP_DATA_DISPINFO;
247         
248         return gpd;
249 }
250
251 /* -------- Data Duplication ---------- */
252
253 /* make a copy of a given gpencil datablock */
254 bGPdata *gpencil_data_duplicate (bGPdata *src)
255 {
256         bGPdata *dst;
257         bGPDlayer *gpld, *gpls;
258         bGPDframe *gpfd, *gpfs;
259         bGPDstroke *gps;
260         
261         /* error checking */
262         if (src == NULL)
263                 return NULL;
264         
265         /* make a copy of the base-data */
266         dst= MEM_dupallocN(src);
267         
268         /* copy layers */
269         duplicatelist(&dst->layers, &src->layers);
270         
271         for (gpld=dst->layers.first, gpls=src->layers.first; gpld && gpls; 
272                  gpld=gpld->next, gpls=gpls->next) 
273         {
274                 /* copy frames */
275                 duplicatelist(&gpld->frames, &gpls->frames);
276                 
277                 for (gpfd=gpld->frames.first, gpfs=gpls->frames.first; gpfd && gpfs;
278                          gpfd=gpfd->next, gpfs=gpfs->next) 
279                 {
280                         /* copy strokes */
281                         duplicatelist(&gpfd->strokes, &gpfs->strokes);
282                         
283                         for (gps= gpfd->strokes.first; gps; gps= gps->next) 
284                         {
285                                 gps->points= MEM_dupallocN(gps->points);
286                         }
287                 }
288         }
289         
290         /* return new */
291         return dst;
292 }
293
294 /* ----------- GP-Datablock API ------------- */
295
296 /* get the appropriate bGPdata from the active/given context */
297 bGPdata *gpencil_data_getactive (ScrArea *sa)
298 {
299         /* error checking */
300         if ((sa == NULL) && (curarea == NULL))
301                 return NULL;
302         if (sa == NULL)
303                 sa= curarea;
304                 
305         /* handle depending on spacetype */
306         switch (sa->spacetype) {
307                 case SPACE_VIEW3D:
308                 {
309                         View3D *v3d= sa->spacedata.first;
310                         return v3d->gpd;
311                 }
312                         break;
313                 case SPACE_NODE:
314                 {
315                         SpaceNode *snode= sa->spacedata.first;
316                         return snode->gpd;
317                 }
318                         break;
319                 case SPACE_SEQ:
320                 {
321                         SpaceSeq *sseq= sa->spacedata.first;
322                         
323                         /* only applicable for image modes */
324                         if (sseq->mainb)
325                                 return sseq->gpd;
326                 }
327                         break;
328                 case SPACE_IMAGE:
329                 {
330                         SpaceImage *sima= sa->spacedata.first;
331                         return sima->gpd;
332                 }
333                         break;
334         }
335         
336         /* nothing found */
337         return NULL;
338 }
339
340 /* set bGPdata for the active/given context, and return success/fail */
341 short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
342 {
343         /* error checking */
344         if ((sa == NULL) && (curarea == NULL))
345                 return 0;
346         if (gpd == NULL)
347                 return 0;
348         if (sa == NULL)
349                 sa= curarea;
350         
351         /* handle depending on spacetype */
352         // TODO: someday we should have multi-user data, so no need to loose old data
353         switch (sa->spacetype) {
354                 case SPACE_VIEW3D:
355                 {
356                         View3D *v3d= sa->spacedata.first;
357                         
358                         /* free the existing block */
359                         if (v3d->gpd)
360                                 free_gpencil_data(v3d->gpd);
361                         v3d->gpd= gpd;
362                         
363                         return 1;
364                 }
365                         break;
366                 case SPACE_NODE:
367                 {
368                         SpaceNode *snode= sa->spacedata.first;
369                         
370                         /* free the existing block */
371                         if (snode->gpd)
372                                 free_gpencil_data(snode->gpd);
373                         snode->gpd= gpd;
374                         
375                         /* set special settings */
376                         gpd->flag |= GP_DATA_VIEWALIGN;
377                         
378                         return 1;
379                 }
380                         break;
381                 case SPACE_SEQ:
382                 {
383                         SpaceSeq *sseq= sa->spacedata.first;
384                         
385                         /* only applicable if right mode */
386                         if (sseq->mainb) {
387                                 /* free the existing block */
388                                 if (sseq->gpd)
389                                         free_gpencil_data(sseq->gpd);
390                                 sseq->gpd= gpd;
391                                 
392                                 return 1;
393                         }
394                 }
395                         break;
396                 case SPACE_IMAGE:
397                 {
398                         SpaceImage *sima= sa->spacedata.first;
399                         
400                         if (sima->gpd)
401                                 free_gpencil_data(sima->gpd);
402                         sima->gpd= gpd;
403                         
404                         return 1;
405                 }
406                         break;
407         }
408         
409         /* failed to add */
410         return 0;
411 }
412
413 /* -------- GP-Frame API ---------- */
414
415 /* delete the last stroke of the given frame */
416 void gpencil_frame_delete_laststroke (bGPDframe *gpf)
417 {
418         bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
419         
420         /* error checking */
421         if (ELEM(NULL, gpf, gps))
422                 return;
423         
424         /* free the stroke and its data */
425         MEM_freeN(gps->points);
426         BLI_freelinkN(&gpf->strokes, gps);
427 }
428
429 /* -------- GP-Layer API ---------- */
430
431 /* get the appropriate gp-frame from a given layer
432  *      - this sets the layer's actframe var (if allowed to)
433  *      - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
434  */
435 bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
436 {
437         bGPDframe *gpf = NULL;
438         short found = 0;
439         
440         /* error checking */
441         if (gpl == NULL) return NULL;
442         if (cframe <= 0) cframe = 1;
443         
444         /* check if there is already an active frame */
445         if (gpl->actframe) {
446                 gpf= gpl->actframe;
447                 
448                 /* do not allow any changes to layer's active frame if layer is locked */
449                 if (gpl->flag & GP_LAYER_LOCKED)
450                         return gpf;
451                 /* do not allow any changes to actframe if frame has painting tag attached to it */
452                 if (gpf->flag & GP_FRAME_PAINT) 
453                         return gpf;
454                 
455                 /* try to find matching frame */
456                 if (gpf->framenum < cframe) {
457                         for (; gpf; gpf= gpf->next) {
458                                 if (gpf->framenum == cframe) {
459                                         found= 1;
460                                         break;
461                                 }
462                                 else if ((gpf->next) && (gpf->next->framenum > cframe)) {
463                                         found= 1;
464                                         break;
465                                 }
466                         }
467                         
468                         /* set the appropriate frame */
469                         if (addnew) {
470                                 if ((found) && (gpf->framenum == cframe))
471                                         gpl->actframe= gpf;
472                                 else
473                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
474                         }
475                         else if (found)
476                                 gpl->actframe= gpf;
477                         else
478                                 gpl->actframe= gpl->frames.last;
479                 }
480                 else {
481                         for (; gpf; gpf= gpf->prev) {
482                                 if (gpf->framenum <= cframe) {
483                                         found= 1;
484                                         break;
485                                 }
486                         }
487                         
488                         /* set the appropriate frame */
489                         if (addnew) {
490                                 if ((found) && (gpf->framenum == cframe))
491                                         gpl->actframe= gpf;
492                                 else
493                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
494                         }
495                         else if (found)
496                                 gpl->actframe= gpf;
497                         else
498                                 gpl->actframe= gpl->frames.first;
499                 }
500         }
501         else if (gpl->frames.first) {
502                 /* check which of the ends to start checking from */
503                 const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
504                 const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
505                 
506                 if (abs(cframe-first) > abs(cframe-last)) {
507                         /* find gp-frame which is less than or equal to cframe */
508                         for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
509                                 if (gpf->framenum <= cframe) {
510                                         found= 1;
511                                         break;
512                                 }
513                         }
514                 }
515                 else {
516                         /* find gp-frame which is less than or equal to cframe */
517                         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
518                                 if (gpf->framenum <= cframe) {
519                                         found= 1;
520                                         break;
521                                 }
522                         }
523                 }
524                 
525                 /* set the appropriate frame */
526                 if (addnew) {
527                         if ((found) && (gpf->framenum == cframe))
528                                 gpl->actframe= gpf;
529                         else
530                                 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
531                 }
532                 else if (found)
533                         gpl->actframe= gpf;
534                 else {
535                         /* unresolved errogenous situation! */
536                         printf("Error: cannot find appropriate gp-frame \n");
537                 }
538         }
539         else {
540                 /* currently no frames (add if allowed to) */
541                 if (addnew)
542                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
543                 else {
544                         /* don't do anything... this may be when no frames yet! */
545                 }
546         }
547         
548         /* return */
549         return gpl->actframe;
550 }
551
552 /* delete the given frame from a layer */
553 void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
554 {
555         /* error checking */
556         if (ELEM(NULL, gpl, gpf))
557                 return;
558                 
559         /* free the frame and its data */
560         free_gpencil_strokes(gpf);
561         BLI_freelinkN(&gpl->frames, gpf);
562         gpl->actframe = NULL;
563 }
564
565 /* get the active gp-layer for editing */
566 bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
567 {
568         bGPDlayer *gpl;
569         
570         /* error checking */
571         if (ELEM(NULL, gpd, gpd->layers.first))
572                 return NULL;
573                 
574         /* loop over layers until found (assume only one active) */
575         for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
576                 if (gpl->flag & GP_LAYER_ACTIVE)
577                         return gpl;
578         }
579         
580         /* no active layer found */
581         return NULL;
582 }
583
584 /* set the active gp-layer */
585 void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
586 {
587         bGPDlayer *gpl;
588         
589         /* error checking */
590         if (ELEM3(NULL, gpd, gpd->layers.first, active))
591                 return;
592                 
593         /* loop over layers deactivating all */
594         for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
595                 gpl->flag &= ~GP_LAYER_ACTIVE;
596         
597         /* set as active one */
598         active->flag |= GP_LAYER_ACTIVE;
599 }
600
601 /* delete the active gp-layer */
602 void gpencil_layer_delactive (bGPdata *gpd)
603 {
604         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
605         
606         /* error checking */
607         if (ELEM(NULL, gpd, gpl)) 
608                 return;
609         
610         /* free layer */        
611         free_gpencil_frames(gpl);
612         BLI_freelinkN(&gpd->layers, gpl);
613
614 }
615
616 /* ************************************************** */
617 /* GREASE-PENCIL EDITING - Tools */
618
619 /* --------- Data Deletion ---------- */
620
621 /* delete the last stroke on the active layer */
622 void gpencil_delete_laststroke (bGPdata *gpd)
623 {
624         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
625         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
626         
627         gpencil_frame_delete_laststroke(gpf);
628 }
629
630 /* delete the active frame */
631 void gpencil_delete_actframe (bGPdata *gpd)
632 {
633         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
634         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
635         
636         gpencil_layer_delframe(gpl, gpf);
637 }
638
639
640
641 /* delete various grase-pencil elements 
642  *      mode:   1 - last stroke
643  *                      2 - active frame
644  *                      3 - active layer
645  */
646 void gpencil_delete_operation (short mode)
647 {
648         bGPdata *gpd;
649         
650         /* get datablock to work on */
651         gpd= gpencil_data_getactive(NULL);
652         if (gpd == NULL) return;
653         
654         switch (mode) {
655                 case 1: /* last stroke */
656                         gpencil_delete_laststroke(gpd);
657                         break;
658                 case 2: /* active frame */
659                         gpencil_delete_actframe(gpd);
660                         break;
661                 case 3: /* active layer */
662                         gpencil_layer_delactive(gpd);
663                         break;
664         }
665         
666         /* redraw and undo-push */
667         BIF_undo_push("GPencil Delete");
668         allqueue(REDRAWVIEW3D, 0);
669 }
670
671 /* display a menu for deleting different grease-pencil elements */
672 void gpencil_delete_menu (void)
673 {
674         bGPdata *gpd= gpencil_data_getactive(NULL);
675         short mode;
676         
677         /* only show menu if it will be relevant */
678         if (gpd == NULL) return;
679         
680         mode= pupmenu("Grease Pencil Erase...%t|Last Stroke%x1|Active Frame%x2|Active Layer%x3");
681         if (mode <= 0) return;
682         
683         gpencil_delete_operation(mode);
684 }
685
686 /* --------- Data Conversion ---------- */
687
688 /* convert the coordinates from the given stroke point into 3d-coordinates */
689 static void gp_strokepoint_convertcoords (bGPDstroke *gps, bGPDspoint *pt, float p3d[3])
690 {
691         if (gps->flag & GP_STROKE_3DSPACE) {
692                 /* directly use 3d-coordinates */
693                 // FIXME: maybe we need to counterotate this for object rotation?
694                 VecCopyf(p3d, &pt->x);
695         }
696         else {
697                 short mval[2], mx, my;
698                 float *fp= give_cursor();
699                 float dvec[3];
700                 
701                 /* get screen coordinate */
702                 if (gps->flag & GP_STROKE_2DSPACE) {
703                         View2D *v2d= spacelink_get_view2d(curarea->spacedata.first);
704                         ipoco_to_areaco_noclip(v2d, &pt->x, mval);
705                 }
706                 else {
707                         mval[0]= (pt->x / 1000 * curarea->winx);
708                         mval[1]= (pt->y / 1000 * curarea->winy);
709                 }
710                 mx= mval[0]; 
711                 my= mval[1];
712                 
713                 /* convert screen coordinate to 3d coordinates 
714                  *      - method taken from editview.c - mouse_cursor() 
715                  */
716                 project_short_noclip(fp, mval);
717                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
718                 VecSubf(p3d, fp, dvec);
719         }
720 }
721
722 /* convert stroke to 3d path */
723 static void gp_layer_to_path (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
724 {
725         bGPDspoint *pt;
726         Nurb *nu;
727         BPoint *bp;
728         int i;
729         
730         /* create new 'nurb' within the curve */
731         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
732         
733         nu->pntsu= gps->totpoints;
734         nu->pntsv= 1;
735         nu->orderu= gps->totpoints;
736         nu->flagu= 2;   /* endpoint */
737         nu->resolu= 32;
738         
739         nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
740         
741         /* add points */
742         for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
743                 float p3d[3];
744                 
745                 /* get coordinates to add at */
746                 gp_strokepoint_convertcoords(gps, pt, p3d);
747                 VecCopyf(bp->vec, p3d);
748                 
749                 /* set settings */
750                 bp->f1= SELECT;
751                 bp->radius = bp->weight = pt->pressure * gpl->thickness;
752         }
753         
754         /* add nurb to curve */
755         BLI_addtail(&cu->nurb, nu);
756 }
757
758 /* convert stroke to 3d bezier */
759 static void gp_layer_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
760 {
761         bGPDspoint *pt;
762         Nurb *nu;
763         BezTriple *bezt;
764         int i;
765         
766         /* create new 'nurb' within the curve */
767         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
768         
769         nu->pntsu= gps->totpoints;
770         nu->resolu= 12;
771         nu->resolv= 12;
772         nu->type= CU_BEZIER;
773         nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
774         
775         /* add points */
776         for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) {
777                 float p3d[3];
778                 
779                 /* get coordinates to add at */
780                 gp_strokepoint_convertcoords(gps, pt, p3d);
781                 
782                 /* TODO: maybe in future the handles shouldn't be in same place */
783                 VecCopyf(bezt->vec[0], p3d);
784                 VecCopyf(bezt->vec[1], p3d);
785                 VecCopyf(bezt->vec[2], p3d);
786                 
787                 /* set settings */
788                 bezt->h1= bezt->h2= HD_FREE;
789                 bezt->f1= bezt->f2= bezt->f3= SELECT;
790                 bezt->radius = bezt->weight = pt->pressure * gpl->thickness;
791         }
792         
793         /* must calculate handles or else we crash */
794         calchandlesNurb(nu);
795         
796         /* add nurb to curve */
797         BLI_addtail(&cu->nurb, nu);
798 }
799
800 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
801 static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl, short mode)
802 {
803         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
804         bGPDstroke *gps;
805         Object *ob;
806         Curve *cu;
807         
808         /* error checking */
809         if (ELEM3(NULL, gpd, gpl, gpf))
810                 return;
811                 
812         /* only convert if there are any strokes on this layer's frame to convert */
813         if (gpf->strokes.first == NULL)
814                 return;
815                 
816         /* initialise the curve */      
817         cu= add_curve(gpl->info, 1);
818         cu->flag |= CU_3D;
819         
820         /* init the curve object (remove rotation and assign curve data to it) */
821         add_object_draw(OB_CURVE);
822         ob= OBACT;
823         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
824         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
825         ob->data= cu;
826         
827         /* add points to curve */
828         for (gps= gpf->strokes.first; gps; gps= gps->next) {
829                 switch (mode) {
830                         case 1: 
831                                 gp_layer_to_path(gpl, gps, cu);
832                                 break;
833                         case 2:
834                                 gp_layer_to_bezier(gpl, gps, cu);
835                                 break;
836                 }
837         }
838 }
839
840 /* convert grease-pencil strokes to another representation 
841  *      mode:   1 - Active layer to path
842  *                      2 - Active layer to bezier
843  */
844 void gpencil_convert_operation (short mode)
845 {
846         bGPdata *gpd;   
847         float *fp= give_cursor();
848         
849         /* get datablock to work on */
850         gpd= gpencil_data_getactive(NULL);
851         if (gpd == NULL) return;
852         
853         /* initialise 3d-cursor correction globals */
854         initgrabz(fp[0], fp[1], fp[2]);
855         
856         /* handle selection modes */
857         switch (mode) {
858                 case 1: /* active layer only (to path) */
859                 case 2: /* active layer only (to bezier) */
860                 {
861                         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
862                         gp_layer_to_curve(gpd, gpl, mode);
863                 }
864                         break;
865         }
866         
867         /* redraw and undo-push */
868         BIF_undo_push("GPencil Convert");
869         allqueue(REDRAWVIEW3D, 0);
870         allqueue(REDRAWOOPS, 0);
871 }
872
873 /* display a menu for converting grease-pencil strokes */
874 void gpencil_convert_menu (void)
875 {
876         bGPdata *gpd= gpencil_data_getactive(NULL);
877         short mode;
878         
879         /* only show menu if it will be relevant */
880         if (gpd == NULL) return;
881         
882         mode= pupmenu("Grease Pencil Convert %t|Active Layer To Path%x1|Active Layer to Bezier%x2");
883         if (mode <= 0) return;
884         
885         gpencil_convert_operation(mode);
886 }
887
888 /* ************************************************** */
889 /* GREASE-PENCIL EDITING MODE - Painting */
890
891 /* ---------- 'Globals' and Defines ----------------- */
892
893 /* maximum sizes of gp-session buffer */
894 #define GP_STROKE_BUFFER_MAX    5000
895
896 /* Hardcoded sensitivity thresholds... */
897 // TODO: one day, these might be added to the UI if it is necessary
898         /* minimum number of pixels mouse should move before new point created */
899 #define MIN_MANHATTEN_PX                3       
900         /* minimum length of new segment before new point can be added */
901 #define MIN_EUCLIDEAN_PX                20
902
903 /* ------ */
904
905 /* Temporary 'Stroke' Operation data */
906 typedef struct tGPsdata {
907         ScrArea *sa;            /* area where painting originated */
908         View2D *v2d;            /* needed for GP_STROKE_2DSPACE */
909         ImBuf *ibuf;            /* needed for GP_STROKE_2DIMAGE */
910         
911         bGPdata *gpd;           /* gp-datablock layer comes from */
912         bGPDlayer *gpl;         /* layer we're working on */
913         bGPDframe *gpf;         /* frame we're working on */
914         
915         short status;           /* current status of painting */
916         short paintmode;        /* mode for painting */
917         
918         short mval[2];          /* current mouse-position */
919         short mvalo[2];         /* previous recorded mouse-position */
920         short radius;           /* radius of influence for eraser */
921 } tGPsdata;
922
923 /* values for tGPsdata->status */
924 enum {
925         GP_STATUS_NORMAL = 0,   /* running normally */
926         GP_STATUS_ERROR,                /* something wasn't correctly set up */
927         GP_STATUS_DONE                  /* painting done */
928 };
929
930 /* values for tGPsdata->paintmode */
931 enum {
932         GP_PAINTMODE_DRAW = 0,
933         GP_PAINTMODE_ERASER
934 };
935
936 /* Return flags for adding points to stroke buffer */
937 enum {
938         GP_STROKEADD_INVALID    = -2,           /* error occurred - insufficient info to do so */
939         GP_STROKEADD_OVERFLOW   = -1,           /* error occurred - cannot fit any more points */
940         GP_STROKEADD_NORMAL,                            /* point was successfully added */
941         GP_STROKEADD_FULL                                       /* cannot add any more points to buffer */
942 };
943
944 /* ---------- Stroke Editing ------------ */
945
946 /* clear the session buffers (call this before AND after a paint operation) */
947 static void gp_session_validatebuffer (tGPsdata *p)
948 {
949         bGPdata *gpd= p->gpd;
950         
951         /* clear memory of buffer (or allocate it if starting a new session) */
952         if (gpd->sbuffer)
953                 memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
954         else
955                 gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
956         
957         /* reset indices */
958         gpd->sbuffer_size = 0;
959         
960         /* reset flags */
961         gpd->sbuffer_sflag= 0;
962 }
963
964 /* init new painting session */
965 static void gp_session_initpaint (tGPsdata *p)
966 {
967         /* clear previous data (note: is on stack) */
968         memset(p, 0, sizeof(tGPsdata));
969         
970         /* make sure the active view (at the starting time) is a 3d-view */
971         if (curarea == NULL) {
972                 p->status= GP_STATUS_ERROR;
973                 if (G.f & G_DEBUG) 
974                         printf("Error: No active view for painting \n");
975                 return;
976         }
977         switch (curarea->spacetype) {
978                 /* supported views first */
979                 case SPACE_VIEW3D:
980                 {
981                         View3D *v3d= curarea->spacedata.first;
982                         
983                         /* set current area */
984                         p->sa= curarea;
985                         
986                         /* check that gpencil data is allowed to be drawn */
987                         if ((v3d->flag2 & V3D_DISPGP)==0) {
988                                 p->status= GP_STATUS_ERROR;
989                                 if (G.f & G_DEBUG) 
990                                         printf("Error: In active view, Grease Pencil not shown \n");
991                                 return;
992                         }
993                 }
994                         break;
995                 case SPACE_NODE:
996                 {
997                         SpaceNode *snode= curarea->spacedata.first;
998                         
999                         /* set current area */
1000                         p->sa= curarea;
1001                         p->v2d= &snode->v2d;
1002                         
1003                         /* check that gpencil data is allowed to be drawn */
1004                         if ((snode->flag & SNODE_DISPGP)==0) {
1005                                 p->status= GP_STATUS_ERROR;
1006                                 if (G.f & G_DEBUG) 
1007                                         printf("Error: In active view, Grease Pencil not shown \n");
1008                                 return;
1009                         }
1010                 }
1011                         break;
1012                 case SPACE_SEQ:
1013                 {
1014                         SpaceSeq *sseq= curarea->spacedata.first;
1015                         
1016                         /* set current area */
1017                         p->sa= curarea;
1018                         p->v2d= &sseq->v2d;
1019                         
1020                         /* check that gpencil data is allowed to be drawn */
1021                         if (sseq->mainb == 0) {
1022                                 p->status= GP_STATUS_ERROR;
1023                                 if (G.f & G_DEBUG) 
1024                                         printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil \n");
1025                                 return;
1026                         }
1027                         if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
1028                                 p->status= GP_STATUS_ERROR;
1029                                 if (G.f & G_DEBUG) 
1030                                         printf("Error: In active view, Grease Pencil not shown \n");
1031                                 return;
1032                         }
1033                 }
1034                         break;  
1035                 case SPACE_IMAGE:
1036                 {
1037                         SpaceImage *sima= curarea->spacedata.first;
1038                         
1039                         /* set the current area */
1040                         p->sa= curarea;
1041                         p->v2d= &sima->v2d;
1042                         //p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1043                 }
1044                         break;
1045                 /* unsupported views */
1046                 default:
1047                 {
1048                         p->status= GP_STATUS_ERROR;
1049                         if (G.f & G_DEBUG) 
1050                                 printf("Error: Active view not appropriate for Grease Pencil drawing \n");
1051                         return;
1052                 }
1053                         break;
1054         }
1055         
1056         /* get gp-data */
1057         p->gpd= gpencil_data_getactive(p->sa);
1058         if (p->gpd == NULL) {
1059                 short ok;
1060                 
1061                 p->gpd= gpencil_data_addnew();
1062                 ok= gpencil_data_setactive(p->sa, p->gpd);
1063                 
1064                 /* most of the time, the following check isn't needed */
1065                 if (ok == 0) {
1066                         /* free gpencil data as it can't be used */
1067                         free_gpencil_data(p->gpd);
1068                         p->gpd= NULL;
1069                         p->status= GP_STATUS_ERROR;
1070                         if (G.f & G_DEBUG) 
1071                                 printf("Error: Could not assign newly created Grease Pencil data to active area \n");
1072                         return;
1073                 }
1074         }
1075         
1076         /* set edit flags */
1077         G.f |= G_GREASEPENCIL;
1078         
1079         /* clear out buffer (stored in gp-data) in case something contaminated it */
1080         gp_session_validatebuffer(p);
1081 }
1082
1083 /* cleanup after a painting session */
1084 static void gp_session_cleanup (tGPsdata *p)
1085 {
1086         bGPdata *gpd= p->gpd;
1087         
1088         /* error checking */
1089         if (gpd == NULL)
1090                 return;
1091         
1092         /* free stroke buffer */
1093         if (gpd->sbuffer) {
1094                 MEM_freeN(gpd->sbuffer);
1095                 gpd->sbuffer= NULL;
1096         }
1097         
1098         /* clear flags */
1099         gpd->sbuffer_size= 0;
1100         gpd->sbuffer_sflag= 0;
1101 }
1102
1103 /* check if the current mouse position is suitable for adding a new point */
1104 static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2])
1105 {
1106         short dx= abs(mval[0] - pmval[0]);
1107         short dy= abs(mval[1] - pmval[1]);
1108         
1109         /* check if mouse moved at least certain distance on both axes (best case) */
1110         if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
1111                 return 1;
1112         
1113         /* check if the distance since the last point is significant enough */
1114         // future optimisation: sqrt here may be too slow?
1115         else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX)
1116                 return 1;
1117         
1118         /* mouse 'didn't move' */
1119         else
1120                 return 0;
1121 }
1122
1123 /* convert screen-coordinates to buffer-coordinates */
1124 static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
1125 {
1126         bGPdata *gpd= p->gpd;
1127         
1128         /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
1129         if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
1130                 const short mx=mval[0], my=mval[1];
1131                 float *fp= give_cursor();
1132                 float dvec[3];
1133                 
1134                 /* method taken from editview.c - mouse_cursor() */
1135                 project_short_noclip(fp, mval);
1136                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
1137                 VecSubf(out, fp, dvec);
1138         }
1139         
1140         /* 2d - on 'canvas' (assume that p->v2d is set) */
1141         else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
1142                 float x, y;
1143                 
1144                 areamouseco_to_ipoco(p->v2d, mval, &x, &y);
1145                 
1146                 out[0]= x;
1147                 out[1]= y;
1148         }
1149         
1150         /* 2d - on image 'canvas' (asume that p->v2d is set) */
1151         else if ( (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) && 
1152                           (p->v2d) && (p->ibuf) ) 
1153         {
1154                 ImBuf *ibuf= p->ibuf;
1155                 float x, y;
1156                 
1157                 /* convert to 'canvas' coordinates, then adjust for view */
1158                 areamouseco_to_ipoco(p->v2d, mval, &x, &y);
1159                 
1160                 if (ibuf) {
1161                         out[0]= x*ibuf->x;
1162                         out[1]= y*ibuf->y;
1163                 }
1164                 else {
1165                         out[0]= x;
1166                         out[1]= y;
1167                 }
1168         }
1169         
1170         /* 2d - relative to screen (viewport area) */
1171         else {
1172                 out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
1173                 out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
1174         }
1175 }
1176
1177 /* add current stroke-point to buffer (returns whether point was successfully added) */
1178 static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
1179 {
1180         bGPdata *gpd= p->gpd;
1181         tGPspoint *pt;
1182         
1183         /* check if still room in buffer */
1184         if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
1185                 return GP_STROKEADD_OVERFLOW;
1186         
1187         /* get pointer to destination point */
1188         pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
1189         
1190         /* store settings */
1191         pt->x= mval[0];
1192         pt->y= mval[1];
1193         pt->pressure= pressure;
1194         
1195         /* increment counters */
1196         gpd->sbuffer_size++;
1197         
1198         /* check if another operation can still occur */
1199         if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
1200                 return GP_STROKEADD_FULL;
1201         else
1202                 return GP_STROKEADD_NORMAL;
1203 }
1204
1205 /* make a new stroke from the buffer data */
1206 static void gp_stroke_newfrombuffer (tGPsdata *p)
1207 {
1208         bGPdata *gpd= p->gpd;
1209         bGPDstroke *gps;
1210         bGPDspoint *pt;
1211         tGPspoint *ptc;
1212         int i, totelem;
1213
1214         /* macro to test if only converting endpoints  */       
1215         #define GP_BUFFER2STROKE_ENDPOINTS ((gpd->flag & GP_DATA_EDITPAINT) && (G.qual & LR_CTRLKEY))
1216         
1217         /* get total number of points to allocate space for:
1218          *      - in 'Draw Mode', holding the Ctrl-Modifier will only take endpoints
1219          *      - otherwise, do whole stroke
1220          */
1221         if (GP_BUFFER2STROKE_ENDPOINTS)
1222                 totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size;
1223         else
1224                 totelem = gpd->sbuffer_size;
1225         
1226         /* exit with error if no valid points from this stroke */
1227         if (totelem == 0) {
1228                 if (G.f & G_DEBUG) 
1229                         printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
1230                 return;
1231         }
1232         
1233         /* allocate memory for a new stroke */
1234         gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
1235         
1236         /* allocate enough memory for a continuous array for storage points */
1237         pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
1238         
1239         /* copy appropriate settings for stroke */
1240         gps->totpoints= totelem;
1241         gps->thickness= p->gpl->thickness;
1242         gps->flag= gpd->sbuffer_sflag;
1243         
1244         /* copy points from the buffer to the stroke */
1245         if (GP_BUFFER2STROKE_ENDPOINTS) {
1246                 /* 'Draw Mode' + Ctrl-Modifier - only endpoints */
1247                 {
1248                         /* first point */
1249                         ptc= gpd->sbuffer;
1250                         
1251                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1252                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1253                         
1254                         /* copy pressure */
1255                         pt->pressure= ptc->pressure;
1256                         
1257                         pt++;
1258                 }
1259                         
1260                 if (totelem == 2) {
1261                         /* last point if applicable */
1262                         ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
1263                         
1264                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1265                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1266                         
1267                         /* copy pressure */
1268                         pt->pressure= ptc->pressure;
1269                 }
1270         }
1271         else {
1272                 /* convert all points (normal behaviour) */
1273                 for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
1274                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1275                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1276                         
1277                         /* copy pressure */
1278                         pt->pressure= ptc->pressure;
1279                         
1280                         pt++;
1281                 }
1282         }
1283         
1284         /* add stroke to frame */
1285         BLI_addtail(&p->gpf->strokes, gps);
1286         
1287         /* undefine macro to test if only converting endpoints  */      
1288         #undef GP_BUFFER2STROKE_ENDPOINTS
1289 }
1290
1291 /* --- 'Eraser' for 'Paint' Tool ------ */
1292
1293 /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
1294 static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
1295 {
1296         bGPDspoint *pt_tmp= gps->points;
1297         bGPDstroke *gsn = NULL;
1298
1299         /* if stroke only had two points, get rid of stroke */
1300         if (gps->totpoints == 2) {
1301                 /* free stroke points, then stroke */
1302                 MEM_freeN(pt_tmp);
1303                 BLI_freelinkN(&gpf->strokes, gps);
1304                 
1305                 /* nothing left in stroke, so stop */
1306                 return 1;
1307         }
1308
1309         /* if last segment, just remove segment from the stroke */
1310         else if (i == gps->totpoints - 2) {
1311                 /* allocate new points array, and assign most of the old stroke there */
1312                 gps->totpoints--;
1313                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1314                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
1315                 
1316                 /* free temp buffer */
1317                 MEM_freeN(pt_tmp);
1318                 
1319                 /* nothing left in stroke, so stop */
1320                 return 1;
1321         }
1322
1323         /* if first segment, just remove segment from the stroke */
1324         else if (i == 0) {
1325                 /* allocate new points array, and assign most of the old stroke there */
1326                 gps->totpoints--;
1327                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1328                 memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
1329                 
1330                 /* free temp buffer */
1331                 MEM_freeN(pt_tmp);
1332                 
1333                 /* no break here, as there might still be stuff to remove in this stroke */
1334                 return 0;
1335         }
1336
1337         /* segment occurs in 'middle' of stroke, so split */
1338         else {
1339                 /* duplicate stroke, and assign 'later' data to that stroke */
1340                 gsn= MEM_dupallocN(gps);
1341                 gsn->prev= gsn->next= NULL;
1342                 BLI_insertlinkafter(&gpf->strokes, gps, gsn);
1343                 
1344                 gsn->totpoints= gps->totpoints - i;
1345                 gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
1346                 memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
1347                 
1348                 /* adjust existing stroke  */
1349                 gps->totpoints= i;
1350                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1351                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
1352                 
1353                 /* free temp buffer */
1354                 MEM_freeN(pt_tmp);
1355                 
1356                 /* nothing left in stroke, so stop */
1357                 return 1;
1358         }
1359 }
1360
1361 /* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
1362 static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1)
1363 {
1364         /* simple within-radius check for now */
1365         if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
1366                 return 1;
1367         
1368         /* not inside */
1369         return 0;
1370
1371
1372 /* eraser tool - evaluation per stroke */
1373 static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
1374 {
1375         bGPDspoint *pt1, *pt2;
1376         short x0=0, y0=0, x1=0, y1=0;
1377         short xyval[2];
1378         int i;
1379         
1380         if (gps->totpoints == 0) {
1381                 /* just free stroke */
1382                 if (gps->points) 
1383                         MEM_freeN(gps->points);
1384                 BLI_freelinkN(&gpf->strokes, gps);
1385         }
1386         else if (gps->totpoints == 1) {
1387                 /* get coordinates */
1388                 if (gps->flag & GP_STROKE_3DSPACE) {
1389                         project_short(&gps->points->x, xyval);
1390                         x0= xyval[0];
1391                         y0= xyval[1];
1392                 }
1393                 else if (gps->flag & GP_STROKE_2DSPACE) {                       
1394                         ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval);
1395                         x0= xyval[0];
1396                         y0= xyval[1];
1397                 }
1398                 else {
1399                         x0= (gps->points->x / 1000 * p->sa->winx);
1400                         y0= (gps->points->y / 1000 * p->sa->winy);
1401                 }
1402                 
1403                 /* do boundbox check first */
1404                 if (BLI_in_rcti(rect, x0, y0)) {
1405                         /* only check if point is inside */
1406                         if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) {
1407                                 /* free stroke */
1408                                 MEM_freeN(gps->points);
1409                                 BLI_freelinkN(&gpf->strokes, gps);
1410                         }
1411                 }
1412         }
1413         else {  
1414                 /* loop over the points in the stroke, checking for intersections 
1415                  *      - an intersection will require the stroke to be split
1416                  */
1417                 for (i=0; (i+1) < gps->totpoints; i++) {
1418                         /* get points to work with */
1419                         pt1= gps->points + i;
1420                         pt2= gps->points + i + 1;
1421                         
1422                         /* get coordinates */
1423                         if (gps->flag & GP_STROKE_3DSPACE) {
1424                                 project_short(&pt1->x, xyval);
1425                                 x0= xyval[0];
1426                                 y0= xyval[1];
1427                                 
1428                                 project_short(&pt2->x, xyval);
1429                                 x1= xyval[0];
1430                                 y1= xyval[1];
1431                         }
1432                         else if (gps->flag & GP_STROKE_2DSPACE) {
1433                                 ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval);
1434                                 x0= xyval[0];
1435                                 y0= xyval[1];
1436                                 
1437                                 ipoco_to_areaco_noclip(p->v2d, &pt2->x, xyval);
1438                                 x1= xyval[0];
1439                                 y1= xyval[1];
1440                         }
1441                         else {
1442                                 x0= (pt1->x / 1000 * p->sa->winx);
1443                                 y0= (pt1->y / 1000 * p->sa->winy);
1444                                 x1= (pt2->x / 1000 * p->sa->winx);
1445                                 y1= (pt2->y / 1000 * p->sa->winy);
1446                         }
1447                         
1448                         /* check that point segment of the boundbox of the eraser stroke */
1449                         if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
1450                                 /* check if point segment of stroke had anything to do with
1451                                  * eraser region  (either within stroke painted, or on its lines)
1452                                  *      - this assumes that linewidth is irrelevant
1453                                  */
1454                                 if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
1455                                         /* if function returns true, break this loop (as no more point to check) */
1456                                         if (gp_stroke_eraser_splitdel(gpf, gps, i))
1457                                                 break;
1458                                 }
1459                         }
1460                 }
1461         }
1462 }
1463
1464 /* -------- */
1465
1466 /* erase strokes which fall under the eraser strokes */
1467 static void gp_stroke_doeraser (tGPsdata *p)
1468 {
1469         bGPDframe *gpf= p->gpf;
1470         bGPDstroke *gps, *gpn;
1471         rcti rect;
1472         
1473         /* rect is rectangle of eraser */
1474         rect.xmin= p->mval[0] - p->radius;
1475         rect.ymin= p->mval[1] - p->radius;
1476         rect.xmax= p->mval[0] + p->radius;
1477         rect.ymax= p->mval[1] + p->radius;
1478         
1479         /* loop over strokes, checking segments for intersections */
1480         for (gps= gpf->strokes.first; gps; gps= gpn) {
1481                 gpn= gps->next;
1482                 gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
1483         }
1484 }
1485
1486 /* ---------- 'Paint' Tool ------------ */
1487
1488 /* init new stroke */
1489 static void gp_paint_initstroke (tGPsdata *p, short paintmode)
1490 {       
1491         /* get active layer (or add a new one if non-existent) */
1492         p->gpl= gpencil_layer_getactive(p->gpd);
1493         if (p->gpl == NULL)
1494                 p->gpl= gpencil_layer_addnew(p->gpd);
1495         if (p->gpl->flag & GP_LAYER_LOCKED) {
1496                 p->status= GP_STATUS_ERROR;
1497                 if (G.f & G_DEBUG)
1498                         printf("Error: Cannot paint on locked layer \n");
1499                 return;
1500         }
1501                 
1502         /* get active frame (add a new one if not matching frame) */
1503         p->gpf= gpencil_layer_getframe(p->gpl, CFRA, 1);
1504         if (p->gpf == NULL) {
1505                 p->status= GP_STATUS_ERROR;
1506                 if (G.f & G_DEBUG) 
1507                         printf("Error: No frame created (gpencil_paint_init) \n");
1508                 return;
1509         }
1510         else
1511                 p->gpf->flag |= GP_FRAME_PAINT;
1512         
1513         /* set 'eraser' for this stroke if using eraser */
1514         p->paintmode= paintmode;
1515         if (p->paintmode == GP_PAINTMODE_ERASER)
1516                 p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
1517         
1518         /* check if points will need to be made in view-aligned space */
1519         if (p->gpd->flag & GP_DATA_VIEWALIGN) {
1520                 switch (p->sa->spacetype) {
1521                         case SPACE_VIEW3D:
1522                         {
1523                                 float *fp= give_cursor();
1524                                 initgrabz(fp[0], fp[1], fp[2]);
1525                                 
1526                                 p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
1527                         }
1528                                 break;
1529                         case SPACE_NODE:
1530                         {
1531                                 p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1532                         }
1533                                 break;
1534                         case SPACE_SEQ:
1535                         {
1536                                 /* for now, this is not applicable here... */
1537                                 //p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1538                         }
1539                                 break;
1540                         case SPACE_IMAGE:
1541                         {
1542                                 p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1543                         }
1544                                 break;
1545                 }
1546         }
1547 }
1548
1549 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1550 static void gp_paint_strokeend (tGPsdata *p)
1551 {
1552         /* check if doing eraser or not */
1553         if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
1554                 /* transfer stroke to frame */
1555                 gp_stroke_newfrombuffer(p);
1556         }
1557         
1558         /* clean up buffer now */
1559         gp_session_validatebuffer(p);
1560 }
1561
1562 /* finish off stroke painting operation */
1563 static void gp_paint_cleanup (tGPsdata *p)
1564 {
1565         /* finish off a stroke */
1566         gp_paint_strokeend(p);
1567         
1568         /* "unlock" frame */
1569         p->gpf->flag &= ~GP_FRAME_PAINT;
1570         
1571         /* add undo-push so stroke can be undone */
1572         /* FIXME: currently disabled, as it's impossible to get this working nice
1573          * as gpenci data is on currently screen-level (which isn't saved to undo files)
1574          */
1575         //BIF_undo_push("GPencil Stroke");
1576         
1577         /* force redraw after drawing action */
1578         force_draw_plus(SPACE_ACTION, 0);
1579 }
1580
1581 /* -------- */
1582
1583 /* main call to paint a new stroke */
1584 short gpencil_paint (short mousebutton, short paintmode)
1585 {
1586         tGPsdata p;
1587         float opressure, pressure;
1588         short ok = GP_STROKEADD_NORMAL;
1589         
1590         /* init paint-data */
1591         gp_session_initpaint(&p);
1592         if (p.status == GP_STATUS_ERROR) {
1593                 gp_session_cleanup(&p);
1594                 return 0;
1595         }
1596         gp_paint_initstroke(&p, paintmode);
1597         if (p.status == GP_STATUS_ERROR) {
1598                 gp_session_cleanup(&p);
1599                 return 0;
1600         }
1601         
1602         /* set cursor to indicate drawing */
1603         setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
1604         
1605         /* init drawing-device settings */
1606         getmouseco_areawin(p.mval);
1607         pressure = get_pressure();
1608         
1609         p.mvalo[0]= p.mval[0];
1610         p.mvalo[1]= p.mval[1];
1611         opressure= pressure;
1612         
1613         /* radius for eraser circle is thickness^2 */
1614         p.radius= p.gpl->thickness * p.gpl->thickness;
1615         
1616         /* start drawing eraser-circle (if applicable) */
1617         if (paintmode == GP_PAINTMODE_ERASER)
1618                 draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again
1619         
1620         /* only allow painting of single 'dots' if: 
1621          *      - pressure is not excessive (as it can be on some windows tablets)
1622          *      - draw-mode for active datablock is turned on
1623          *      - not erasing
1624          */
1625         if (paintmode != GP_PAINTMODE_ERASER) {
1626                 if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { 
1627                         gp_stroke_addpoint(&p, p.mval, pressure);
1628                 }
1629         }
1630         
1631         /* paint loop */
1632         do {
1633                 /* get current user input */
1634                 getmouseco_areawin(p.mval);
1635                 pressure = get_pressure();
1636                 
1637                 /* only add current point to buffer if mouse moved (otherwise wait until it does) */
1638                 if (paintmode == GP_PAINTMODE_ERASER) {
1639                         /* do 'live' erasing now */
1640                         gp_stroke_doeraser(&p);
1641                         
1642                         draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0);
1643                         force_draw(0);
1644                         
1645                         p.mvalo[0]= p.mval[0];
1646                         p.mvalo[1]= p.mval[1];
1647                 }
1648                 else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) {
1649                         /* try to add point */
1650                         ok= gp_stroke_addpoint(&p, p.mval, pressure);
1651                         
1652                         /* handle errors while adding point */
1653                         if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
1654                                 /* finish off old stroke */
1655                                 gp_paint_strokeend(&p);
1656                                 
1657                                 /* start a new stroke, starting from previous point */
1658                                 gp_stroke_addpoint(&p, p.mvalo, opressure);
1659                                 ok= gp_stroke_addpoint(&p, p.mval, pressure);
1660                         }
1661                         else if (ok == GP_STROKEADD_INVALID) {
1662                                 /* the painting operation cannot continue... */
1663                                 error("Cannot paint stroke");
1664                                 p.status = GP_STATUS_ERROR;
1665                                 
1666                                 if (G.f & G_DEBUG) 
1667                                         printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
1668                                 break;
1669                         }
1670                         force_draw(0);
1671                         
1672                         p.mvalo[0]= p.mval[0];
1673                         p.mvalo[1]= p.mval[1];
1674                         opressure= pressure;
1675                 }
1676                 else
1677                         BIF_wait_for_statechange();
1678                 
1679                 /* do mouse checking at the end, so don't check twice, and potentially
1680                  * miss a short tap 
1681                  */
1682         } while (get_mbut() & mousebutton);
1683         
1684         /* clear edit flags */
1685         G.f &= ~G_GREASEPENCIL;
1686         
1687         /* restore cursor to indicate end of drawing */
1688         setcursor_space(p.sa->spacetype, CURSOR_STD);
1689         
1690         /* check size of buffer before cleanup, to determine if anything happened here */
1691         if (paintmode == GP_PAINTMODE_ERASER) {
1692                 ok= 1; // fixme
1693                 draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0);
1694         }
1695         else
1696                 ok= p.gpd->sbuffer_size;
1697         
1698         /* cleanup */
1699         gp_paint_cleanup(&p);
1700         gp_session_cleanup(&p);
1701         
1702         /* done! return if a stroke was successfully added */
1703         return ok;
1704 }
1705
1706
1707 /* All event (loops) handling checking if stroke drawing should be initiated
1708  * should call this function.
1709  */
1710 short gpencil_do_paint (ScrArea *sa, short mbut)
1711 {
1712         bGPdata *gpd = gpencil_data_getactive(sa);
1713         short retval= 0;
1714         
1715         /* check if possible to do painting */
1716         if (gpd == NULL) 
1717                 return 0;
1718         
1719         /* currently, we will only 'paint' if:
1720          *      1. draw-mode on gpd is set (for accessibility reasons)
1721          *              a) single dots are only available by this method if a single click is made
1722          *              b) a straight line is drawn if ctrl-modifier is held (check is done when stroke is converted!)
1723          *      2. if shift-modifier is held + lmb -> 'quick paint'
1724          *
1725          *      OR
1726          * 
1727          * draw eraser stroke if:
1728          *      1. using the eraser on a tablet
1729          *      2. draw-mode on gpd is set (for accessiblity reasons)
1730          *              (eraser is mapped to right-mouse)
1731          *      3. Alt + 'select' mouse-button
1732          *              i.e.  if LMB = select: Alt-LMB
1733          *                        if RMB = select: Alt-RMB
1734          */
1735         if (get_activedevice() == 2) {
1736                 /* eraser on a tablet - always try to erase strokes */
1737                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1738         }
1739         else if (gpd->flag & GP_DATA_EDITPAINT) {
1740                 /* try to paint/erase */
1741                 if (mbut == L_MOUSE)
1742                         retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
1743                 else if (mbut == R_MOUSE)
1744                         retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1745         }
1746         else if (!(gpd->flag & GP_DATA_LMBPLOCK)) {
1747                 /* try to paint/erase as not locked */
1748                 if ((G.qual == LR_SHIFTKEY) && (mbut == L_MOUSE)) {
1749                         retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
1750                 }
1751                 else if (G.qual == LR_ALTKEY) {
1752                         if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE))
1753                                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1754                         else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE))
1755                                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1756                 }
1757         }
1758         
1759         /* return result of trying to paint */
1760         return retval;
1761 }
1762
1763 /* ************************************************** */