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