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