UI: various changes
[blender-staging.git] / source / blender / editors / gpencil / gpencil.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008, Blender Foundation
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 #include "MEM_guardedalloc.h"
35
36 #include "BMF_Api.h"
37
38 #include "IMB_imbuf.h"
39 #include "IMB_imbuf_types.h"
40
41 #include "BLI_arithb.h"
42 #include "BLI_blenlib.h"
43
44 #include "DNA_listBase.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_curve_types.h"
47 #include "DNA_gpencil_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_userdef_types.h"
53 #include "DNA_vec_types.h"
54 #include "DNA_view3d_types.h"
55
56 #include "BKE_armature.h"
57 #include "BKE_blender.h"
58 #include "BKE_context.h"
59 #include "BKE_curve.h"
60 #include "BKE_global.h"
61 #include "BKE_image.h"
62 #include "BKE_library.h"
63 #include "BKE_utildefines.h"
64
65 #include "BIF_gl.h"
66 #include "BIF_glutil.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "UI_view2d.h"
72
73 #include "ED_armature.h"
74 #include "ED_gpencil.h"
75 #include "ED_sequencer.h"
76 #include "ED_view3d.h"
77
78 #include "PIL_time.h"                   /* sleep                                */
79
80 #include "gpencil_intern.h"
81
82 /* XXX */
83 static void BIF_undo_push() {}
84 static void error() {}
85 static int pupmenu() {return 0;}
86 static void add_object_draw() {}
87 static int get_activedevice() {return 0;}
88 #define L_MOUSE 0
89 #define R_MOUSE 0
90
91 /* XXX */
92
93 /* ************************************************** */
94 /* GENERAL STUFF */
95
96 /* --------- Memory Management ------------ */
97
98 /* Free strokes belonging to a gp-frame */
99 void free_gpencil_strokes (bGPDframe *gpf)
100 {
101         bGPDstroke *gps, *gpsn;
102         
103         /* error checking */
104         if (gpf == NULL) return;
105         
106         /* free strokes */
107         for (gps= gpf->strokes.first; gps; gps= gpsn) {
108                 gpsn= gps->next;
109                 
110                 /* free stroke memory arrays, then stroke itself */
111                 if (gps->points) MEM_freeN(gps->points);
112                 BLI_freelinkN(&gpf->strokes, gps);
113         }
114 }
115
116 /* Free all of a gp-layer's frames */
117 void free_gpencil_frames (bGPDlayer *gpl)
118 {
119         bGPDframe *gpf, *gpfn;
120         
121         /* error checking */
122         if (gpl == NULL) return;
123         
124         /* free frames */
125         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
126                 gpfn= gpf->next;
127                 
128                 /* free strokes and their associated memory */
129                 free_gpencil_strokes(gpf);
130                 BLI_freelinkN(&gpl->frames, gpf);
131         }
132 }
133
134 /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
135 void free_gpencil_layers (ListBase *list) 
136 {
137         bGPDlayer *gpl, *gpln;
138         
139         /* error checking */
140         if (list == NULL) return;
141         
142         /* delete layers*/
143         for (gpl= list->first; gpl; gpl= gpln) {
144                 gpln= gpl->next;
145                 
146                 /* free layers and their data */
147                 free_gpencil_frames(gpl);
148                 BLI_freelinkN(list, gpl);
149         }
150 }
151
152 /* Free gp-data and all it's related data */
153 void free_gpencil_data (bGPdata *gpd)
154 {
155         /* free layers then data itself */
156         free_gpencil_layers(&gpd->layers);
157         MEM_freeN(gpd);
158 }
159
160 /* -------- Container Creation ---------- */
161
162 /* add a new gp-frame to the given layer */
163 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
164 {
165         bGPDframe *gpf, *gf;
166         short state=0;
167         
168         /* error checking */
169         if ((gpl == NULL) || (cframe <= 0))
170                 return NULL;
171                 
172         /* allocate memory for this frame */
173         gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
174         gpf->framenum= cframe;
175         
176         /* find appropriate place to add frame */
177         if (gpl->frames.first) {
178                 for (gf= gpl->frames.first; gf; gf= gf->next) {
179                         /* check if frame matches one that is supposed to be added */
180                         if (gf->framenum == cframe) {
181                                 state= -1;
182                                 break;
183                         }
184                         
185                         /* if current frame has already exceeded the frame to add, add before */
186                         if (gf->framenum > cframe) {
187                                 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
188                                 state= 1;
189                                 break;
190                         }
191                 }
192         }
193         
194         /* check whether frame was added successfully */
195         if (state == -1) {
196                 MEM_freeN(gpf);
197                 printf("Error: frame (%d) existed already for this layer \n", cframe);
198         }
199         else if (state == 0) {
200                 /* add to end then! */
201                 BLI_addtail(&gpl->frames, gpf);
202         }
203         
204         /* return frame */
205         return gpf;
206 }
207
208 /* add a new gp-layer and make it the active layer */
209 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
210 {
211         bGPDlayer *gpl;
212         
213         /* check that list is ok */
214         if (gpd == NULL)
215                 return NULL;
216                 
217         /* allocate memory for frame and add to end of list */
218         gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
219         
220         /* add to datablock */
221         BLI_addtail(&gpd->layers, gpl);
222         
223         /* set basic settings */
224         gpl->color[3]= 0.9f;
225         gpl->thickness = 3;
226         
227         /* auto-name */
228         sprintf(gpl->info, "GP_Layer");
229         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
230         
231         /* make this one the active one */
232         gpencil_layer_setactive(gpd, gpl);
233         
234         /* return layer */
235         return gpl;
236 }
237
238 /* add a new gp-datablock */
239 bGPdata *gpencil_data_addnew (void)
240 {
241         bGPdata *gpd;
242         
243         /* allocate memory for a new block */
244         gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
245         
246         /* initial settings */
247         gpd->flag = (GP_DATA_DISPINFO|GP_DATA_EXPAND);
248         
249         return gpd;
250 }
251
252 /* -------- Data Duplication ---------- */
253
254 /* make a copy of a given gpencil frame */
255 bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
256 {
257         bGPDstroke *gps, *gpsd;
258         bGPDframe *dst;
259         
260         /* error checking */
261         if (src == NULL)
262                 return NULL;
263                 
264         /* make a copy of the source frame */
265         dst= MEM_dupallocN(src);
266         dst->prev= dst->next= NULL;
267         
268         /* copy strokes */
269         dst->strokes.first = dst->strokes.last= NULL;
270         for (gps= src->strokes.first; gps; gps= gps->next) {
271                 /* make copy of source stroke, then adjust pointer to points too */
272                 gpsd= MEM_dupallocN(gps);
273                 gpsd->points= MEM_dupallocN(gps->points);
274                 
275                 BLI_addtail(&dst->strokes, gpsd);
276         }
277         
278         /* return new frame */
279         return dst;
280 }
281
282 /* make a copy of a given gpencil layer */
283 bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src)
284 {
285         bGPDframe *gpf, *gpfd;
286         bGPDlayer *dst;
287         
288         /* error checking */
289         if (src == NULL)
290                 return NULL;
291                 
292         /* make a copy of source layer */
293         dst= MEM_dupallocN(src);
294         dst->prev= dst->next= NULL;
295         
296         /* copy frames */
297         dst->frames.first= dst->frames.last= NULL;
298         for (gpf= src->frames.first; gpf; gpf= gpf->next) {
299                 /* make a copy of source frame */
300                 gpfd= gpencil_frame_duplicate(gpf);
301                 BLI_addtail(&dst->frames, gpfd);
302                 
303                 /* if source frame was the current layer's 'active' frame, reassign that too */
304                 if (gpf == dst->actframe)
305                         dst->actframe= gpfd;
306         }
307         
308         /* return new layer */
309         return dst;
310 }
311
312 /* make a copy of a given gpencil datablock */
313 bGPdata *gpencil_data_duplicate (bGPdata *src)
314 {
315         bGPDlayer *gpl, *gpld;
316         bGPdata *dst;
317         
318         /* error checking */
319         if (src == NULL)
320                 return NULL;
321         
322         /* make a copy of the base-data */
323         dst= MEM_dupallocN(src);
324         
325         /* copy layers */
326         dst->layers.first= dst->layers.last= NULL;
327         for (gpl= src->layers.first; gpl; gpl= gpl->next) {
328                 /* make a copy of source layer and its data */
329                 gpld= gpencil_layer_duplicate(gpl);
330                 BLI_addtail(&dst->layers, gpld);
331         }
332         
333         /* return new */
334         return dst;
335 }
336
337 /* ----------- GP-Datablock API ------------- */
338
339 /* get the appropriate bGPdata from the active/given context */
340 // XXX region or region data?
341 bGPdata *gpencil_data_getactive (ScrArea *sa)
342 {
343         ScrArea *curarea= NULL; // XXX
344         
345         /* error checking */
346         if ((sa == NULL) && (curarea == NULL))
347                 return NULL;
348         if (sa == NULL)
349                 sa= curarea;
350                 
351         /* handle depending on spacetype */
352         switch (sa->spacetype) {
353                 case SPACE_VIEW3D:
354                 {
355                         View3D *v3d= sa->spacedata.first;
356                         return v3d->gpd;
357                 }
358                         break;
359                 case SPACE_NODE:
360                 {
361                         SpaceNode *snode= sa->spacedata.first;
362                         return snode->gpd;
363                 }
364                         break;
365                 case SPACE_SEQ:
366                 {
367                         SpaceSeq *sseq= sa->spacedata.first;
368                         
369                         /* only applicable for image modes */
370                         if (sseq->mainb)
371                                 return sseq->gpd;
372                 }
373                         break;
374                 case SPACE_IMAGE:
375                 {
376                         SpaceImage *sima= sa->spacedata.first;
377                         return sima->gpd;
378                 }
379                         break;
380         }
381         
382         /* nothing found */
383         return NULL;
384 }
385
386 /* set bGPdata for the active/given context, and return success/fail */
387 short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
388 {
389         ScrArea *curarea= NULL; // XXX
390         
391         /* error checking */
392         if ((sa == NULL) && (curarea == NULL))
393                 return 0;
394         if (gpd == NULL)
395                 return 0;
396         if (sa == NULL)
397                 sa= curarea;
398         
399         /* handle depending on spacetype */
400         // TODO: someday we should have multi-user data, so no need to loose old data
401         switch (sa->spacetype) {
402                 case SPACE_VIEW3D:
403                 {
404                         View3D *v3d= sa->spacedata.first;
405                         
406                         /* free the existing block */
407                         if (v3d->gpd)
408                                 free_gpencil_data(v3d->gpd);
409                         v3d->gpd= gpd;
410                         
411                         return 1;
412                 }
413                         break;
414                 case SPACE_NODE:
415                 {
416                         SpaceNode *snode= sa->spacedata.first;
417                         
418                         /* free the existing block */
419                         if (snode->gpd)
420                                 free_gpencil_data(snode->gpd);
421                         snode->gpd= gpd;
422                         
423                         /* set special settings */
424                         gpd->flag |= GP_DATA_VIEWALIGN;
425                         
426                         return 1;
427                 }
428                         break;
429                 case SPACE_SEQ:
430                 {
431                         SpaceSeq *sseq= sa->spacedata.first;
432                         
433                         /* only applicable if right mode */
434                         if (sseq->mainb) {
435                                 /* free the existing block */
436                                 if (sseq->gpd)
437                                         free_gpencil_data(sseq->gpd);
438                                 sseq->gpd= gpd;
439                                 
440                                 return 1;
441                         }
442                 }
443                         break;
444                 case SPACE_IMAGE:
445                 {
446                         SpaceImage *sima= sa->spacedata.first;
447                         
448                         if (sima->gpd)
449                                 free_gpencil_data(sima->gpd);
450                         sima->gpd= gpd;
451                         
452                         return 1;
453                 }
454                         break;
455         }
456         
457         /* failed to add */
458         return 0;
459 }
460
461 /* return the ScrArea that has the given GP-datablock
462  *      - assumes that only searching in current screen
463  *      - is based on GP-datablocks only being able to 
464  *        exist for one area at a time (i.e. not multiuser)
465  */
466 ScrArea *gpencil_data_findowner (bGPdata *gpd)
467 {
468         bScreen *curscreen= NULL; // XXX
469         ScrArea *sa;
470         
471         /* error checking */
472         if (gpd == NULL)
473                 return NULL;
474                 
475         /* loop over all scrareas for current screen, and check if that area has this gpd */
476         for (sa= curscreen->areabase.first; sa; sa= sa->next) {
477                 /* use get-active func to see if match */
478                 if (gpencil_data_getactive(sa) == gpd)
479                         return sa;
480         }
481         
482         /* not found */
483         return NULL;
484 }
485
486 /* -------- GP-Frame API ---------- */
487
488 /* delete the last stroke of the given frame */
489 void gpencil_frame_delete_laststroke (bGPDframe *gpf)
490 {
491         bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
492         
493         /* error checking */
494         if (ELEM(NULL, gpf, gps))
495                 return;
496         
497         /* free the stroke and its data */
498         MEM_freeN(gps->points);
499         BLI_freelinkN(&gpf->strokes, gps);
500 }
501
502 /* -------- GP-Layer API ---------- */
503
504 /* get the appropriate gp-frame from a given layer
505  *      - this sets the layer's actframe var (if allowed to)
506  *      - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
507  */
508 bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
509 {
510         bGPDframe *gpf = NULL;
511         short found = 0;
512         
513         /* error checking */
514         if (gpl == NULL) return NULL;
515         if (cframe <= 0) cframe = 1;
516         
517         /* check if there is already an active frame */
518         if (gpl->actframe) {
519                 gpf= gpl->actframe;
520                 
521                 /* do not allow any changes to layer's active frame if layer is locked */
522                 if (gpl->flag & GP_LAYER_LOCKED)
523                         return gpf;
524                 /* do not allow any changes to actframe if frame has painting tag attached to it */
525                 if (gpf->flag & GP_FRAME_PAINT) 
526                         return gpf;
527                 
528                 /* try to find matching frame */
529                 if (gpf->framenum < cframe) {
530                         for (; gpf; gpf= gpf->next) {
531                                 if (gpf->framenum == cframe) {
532                                         found= 1;
533                                         break;
534                                 }
535                                 else if ((gpf->next) && (gpf->next->framenum > cframe)) {
536                                         found= 1;
537                                         break;
538                                 }
539                         }
540                         
541                         /* set the appropriate frame */
542                         if (addnew) {
543                                 if ((found) && (gpf->framenum == cframe))
544                                         gpl->actframe= gpf;
545                                 else
546                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
547                         }
548                         else if (found)
549                                 gpl->actframe= gpf;
550                         else
551                                 gpl->actframe= gpl->frames.last;
552                 }
553                 else {
554                         for (; gpf; gpf= gpf->prev) {
555                                 if (gpf->framenum <= cframe) {
556                                         found= 1;
557                                         break;
558                                 }
559                         }
560                         
561                         /* set the appropriate frame */
562                         if (addnew) {
563                                 if ((found) && (gpf->framenum == cframe))
564                                         gpl->actframe= gpf;
565                                 else
566                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
567                         }
568                         else if (found)
569                                 gpl->actframe= gpf;
570                         else
571                                 gpl->actframe= gpl->frames.first;
572                 }
573         }
574         else if (gpl->frames.first) {
575                 /* check which of the ends to start checking from */
576                 const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
577                 const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
578                 
579                 if (abs(cframe-first) > abs(cframe-last)) {
580                         /* find gp-frame which is less than or equal to cframe */
581                         for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
582                                 if (gpf->framenum <= cframe) {
583                                         found= 1;
584                                         break;
585                                 }
586                         }
587                 }
588                 else {
589                         /* find gp-frame which is less than or equal to cframe */
590                         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
591                                 if (gpf->framenum <= cframe) {
592                                         found= 1;
593                                         break;
594                                 }
595                         }
596                 }
597                 
598                 /* set the appropriate frame */
599                 if (addnew) {
600                         if ((found) && (gpf->framenum == cframe))
601                                 gpl->actframe= gpf;
602                         else
603                                 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
604                 }
605                 else if (found)
606                         gpl->actframe= gpf;
607                 else {
608                         /* unresolved errogenous situation! */
609                         printf("Error: cannot find appropriate gp-frame \n");
610                         /* gpl->actframe should still be NULL */
611                 }
612         }
613         else {
614                 /* currently no frames (add if allowed to) */
615                 if (addnew)
616                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
617                 else {
618                         /* don't do anything... this may be when no frames yet! */
619                         /* gpl->actframe should still be NULL */
620                 }
621         }
622         
623         /* return */
624         return gpl->actframe;
625 }
626
627 /* delete the given frame from a layer */
628 void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
629 {
630         /* error checking */
631         if (ELEM(NULL, gpl, gpf))
632                 return;
633                 
634         /* free the frame and its data */
635         free_gpencil_strokes(gpf);
636         BLI_freelinkN(&gpl->frames, gpf);
637         gpl->actframe = NULL;
638 }
639
640 /* get the active gp-layer for editing */
641 bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
642 {
643         bGPDlayer *gpl;
644         
645         /* error checking */
646         if (ELEM(NULL, gpd, gpd->layers.first))
647                 return NULL;
648                 
649         /* loop over layers until found (assume only one active) */
650         for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
651                 if (gpl->flag & GP_LAYER_ACTIVE)
652                         return gpl;
653         }
654         
655         /* no active layer found */
656         return NULL;
657 }
658
659 /* set the active gp-layer */
660 void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
661 {
662         bGPDlayer *gpl;
663         
664         /* error checking */
665         if (ELEM3(NULL, gpd, gpd->layers.first, active))
666                 return;
667                 
668         /* loop over layers deactivating all */
669         for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
670                 gpl->flag &= ~GP_LAYER_ACTIVE;
671         
672         /* set as active one */
673         active->flag |= GP_LAYER_ACTIVE;
674 }
675
676 /* delete the active gp-layer */
677 void gpencil_layer_delactive (bGPdata *gpd)
678 {
679         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
680         
681         /* error checking */
682         if (ELEM(NULL, gpd, gpl)) 
683                 return;
684         
685         /* free layer */        
686         free_gpencil_frames(gpl);
687         BLI_freelinkN(&gpd->layers, gpl);
688 }
689
690 /* ************************************************** */
691 /* GREASE-PENCIL EDITING - Tools */
692
693 /* --------- Data Deletion ---------- */
694
695 /* delete the last stroke on the active layer */
696 void gpencil_delete_laststroke (bGPdata *gpd, int cfra)
697 {
698         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
699         bGPDframe *gpf= gpencil_layer_getframe(gpl, cfra, 0);
700         
701         gpencil_frame_delete_laststroke(gpf);
702 }
703
704 /* delete the active frame */
705 void gpencil_delete_actframe (bGPdata *gpd, int cfra)
706 {
707         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
708         bGPDframe *gpf= gpencil_layer_getframe(gpl, cfra, 0);
709         
710         gpencil_layer_delframe(gpl, gpf);
711 }
712
713
714
715 /* delete various grase-pencil elements 
716  *      mode:   1 - last stroke
717  *                      2 - active frame
718  *                      3 - active layer
719  */
720 void gpencil_delete_operation (int cfra, short mode)
721 {
722         bGPdata *gpd;
723         
724         /* get datablock to work on */
725         gpd= gpencil_data_getactive(NULL);
726         if (gpd == NULL) return;
727         
728         switch (mode) {
729                 case 1: /* last stroke */
730                         gpencil_delete_laststroke(gpd, cfra);
731                         break;
732                 case 2: /* active frame */
733                         gpencil_delete_actframe(gpd, cfra);
734                         break;
735                 case 3: /* active layer */
736                         gpencil_layer_delactive(gpd);
737                         break;
738         }
739         
740         /* redraw and undo-push */
741         BIF_undo_push("GPencil Delete");
742 }
743
744 /* display a menu for deleting different grease-pencil elements */
745 void gpencil_delete_menu (void)
746 {
747         bGPdata *gpd= gpencil_data_getactive(NULL);
748         int cfra= 0; // XXX
749         short mode;
750         
751         /* only show menu if it will be relevant */
752         if (gpd == NULL) return;
753         
754         mode= pupmenu("Grease Pencil Erase...%t|Last Stroke%x1|Active Frame%x2|Active Layer%x3");
755         if (mode <= 0) return;
756         
757         gpencil_delete_operation(cfra, mode);
758 }
759
760 /* --------- Data Conversion ---------- */
761
762 /* convert the coordinates from the given stroke point into 3d-coordinates */
763 static void gp_strokepoint_convertcoords (bGPDstroke *gps, bGPDspoint *pt, float p3d[3])
764 {
765         ARegion *ar= NULL; // XXX
766         View3D *v3d= NULL; // XXX
767         
768         if (gps->flag & GP_STROKE_3DSPACE) {
769                 /* directly use 3d-coordinates */
770                 VecCopyf(p3d, &pt->x);
771         }
772         else {
773                 short mval[2];
774                 int mx, my;
775                 float *fp= give_cursor(NULL, NULL); // XXX should be scene, v3d
776                 float dvec[3];
777                 
778                 /* get screen coordinate */
779                 if (gps->flag & GP_STROKE_2DSPACE) {
780                         // XXX
781                         // View2D *v2d= spacelink_get_view2d(curarea->spacedata.first);
782                         // UI_view2d_view_to_region(v2d, pt->x, pt->y, &mx, &my);
783                 }
784                 else {
785                         // XXX
786                         // mx= (short)(pt->x / 1000 * curarea->winx);
787                         // my= (short)(pt->y / 1000 * curarea->winy);
788                 }
789                 
790                 /* convert screen coordinate to 3d coordinates 
791                  *      - method taken from editview.c - mouse_cursor() 
792                  */
793                 project_short_noclip(ar, v3d, fp, mval);
794                 window_to_3d(ar, v3d, dvec, mval[0]-mx, mval[1]-my);
795                 VecSubf(p3d, fp, dvec);
796         }
797 }
798
799 /* --- */
800
801 /* convert stroke to 3d path */
802 static void gp_stroke_to_path (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
803 {
804         bGPDspoint *pt;
805         Nurb *nu;
806         BPoint *bp;
807         int i;
808         
809         /* create new 'nurb' within the curve */
810         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
811         
812         nu->pntsu= gps->totpoints;
813         nu->pntsv= 1;
814         nu->orderu= gps->totpoints;
815         nu->flagu= 2;   /* endpoint */
816         nu->resolu= 32;
817         
818         nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
819         
820         /* add points */
821         for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
822                 float p3d[3];
823                 
824                 /* get coordinates to add at */
825                 gp_strokepoint_convertcoords(gps, pt, p3d);
826                 VecCopyf(bp->vec, p3d);
827                 
828                 /* set settings */
829                 bp->f1= SELECT;
830                 bp->radius = bp->weight = pt->pressure * gpl->thickness;
831         }
832         
833         /* add nurb to curve */
834         BLI_addtail(&cu->nurb, nu);
835 }
836
837 /* convert stroke to 3d bezier */
838 static void gp_stroke_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
839 {
840         bGPDspoint *pt;
841         Nurb *nu;
842         BezTriple *bezt;
843         int i;
844         
845         /* create new 'nurb' within the curve */
846         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
847         
848         nu->pntsu= gps->totpoints;
849         nu->resolu= 12;
850         nu->resolv= 12;
851         nu->type= CU_BEZIER;
852         nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
853         
854         /* add points */
855         for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) {
856                 float p3d[3];
857                 
858                 /* get coordinates to add at */
859                 gp_strokepoint_convertcoords(gps, pt, p3d);
860                 
861                 /* TODO: maybe in future the handles shouldn't be in same place */
862                 VecCopyf(bezt->vec[0], p3d);
863                 VecCopyf(bezt->vec[1], p3d);
864                 VecCopyf(bezt->vec[2], p3d);
865                 
866                 /* set settings */
867                 bezt->h1= bezt->h2= HD_FREE;
868                 bezt->f1= bezt->f2= bezt->f3= SELECT;
869                 bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f;
870         }
871         
872         /* must calculate handles or else we crash */
873         calchandlesNurb(nu);
874         
875         /* add nurb to curve */
876         BLI_addtail(&cu->nurb, nu);
877 }
878
879 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
880 static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl, Scene *scene, short mode)
881 {
882         bGPDframe *gpf= gpencil_layer_getframe(gpl, scene->r.cfra, 0);
883         bGPDstroke *gps;
884         Object *ob;
885         Curve *cu;
886         
887         /* error checking */
888         if (ELEM3(NULL, gpd, gpl, gpf))
889                 return;
890                 
891         /* only convert if there are any strokes on this layer's frame to convert */
892         if (gpf->strokes.first == NULL)
893                 return;
894         
895         /* init the curve object (remove rotation and get curve data from it)
896          *      - must clear transforms set on object, as those skew our results
897          */
898         add_object_draw(OB_CURVE);
899         ob= OBACT;
900         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
901         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
902         cu= ob->data;
903         cu->flag |= CU_3D;
904         
905         /* rename object and curve to layer name */
906         rename_id((ID *)ob, gpl->info);
907         rename_id((ID *)cu, gpl->info);
908         
909         /* add points to curve */
910         for (gps= gpf->strokes.first; gps; gps= gps->next) {
911                 switch (mode) {
912                         case 1: 
913                                 gp_stroke_to_path(gpl, gps, cu);
914                                 break;
915                         case 2:
916                                 gp_stroke_to_bezier(gpl, gps, cu);
917                                 break;
918                 }
919         }
920 }
921
922 /* --- */
923
924 /* convert a stroke to a bone chain */
925 static void gp_stroke_to_bonechain (bGPDlayer *gpl, bGPDstroke *gps, bArmature *arm, ListBase *bones)
926 {
927         EditBone *ebo, *prev=NULL;
928         bGPDspoint *pt, *ptn;
929         int i;
930         
931         /* add each segment separately */
932         for (i=0, pt=gps->points, ptn=gps->points+1; i < (gps->totpoints-1); prev=ebo, i++, pt++, ptn++) {
933                 float p3da[3], p3db[3];
934                 
935                 /* get coordinates to add at */
936                 gp_strokepoint_convertcoords(gps, pt, p3da);
937                 gp_strokepoint_convertcoords(gps, ptn, p3db);
938                 
939                 /* allocate new bone */
940                 ebo= MEM_callocN(sizeof(EditBone), "eBone");
941                 
942                 VecCopyf(ebo->head, p3da);
943                 VecCopyf(ebo->tail, p3db);
944                 
945                 /* add new bone - note: sync with editarmature.c::add_editbone() */
946                 {
947                         BLI_strncpy(ebo->name, "Stroke", 32);
948                         unique_editbone_name(bones, ebo->name);
949                         
950                         BLI_addtail(bones, ebo);
951                         
952                         if (i > 0)
953                         {
954                                 ebo->flag |= BONE_CONNECTED;
955                         }
956                         ebo->weight= 1.0f;
957                         ebo->dist= 0.25f;
958                         ebo->xwidth= 0.1f;
959                         ebo->zwidth= 0.1f;
960                         ebo->ease1= 1.0f;
961                         ebo->ease2= 1.0f;
962                         ebo->rad_head= pt->pressure * gpl->thickness * 0.1f;
963                         ebo->rad_tail= ptn->pressure * gpl->thickness * 0.1f;
964                         ebo->segments= 1;
965                         ebo->layer= arm->layer;
966                 }
967                 
968                 /* set parenting */
969                 ebo->parent= prev;
970         }
971 }
972
973 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
974 static void gp_layer_to_armature (bGPdata *gpd, bGPDlayer *gpl, Scene *scene, View3D *v3d, short mode)
975 {
976         bGPDframe *gpf= gpencil_layer_getframe(gpl, scene->r.cfra, 0);
977         bGPDstroke *gps;
978         Object *ob;
979         bArmature *arm;
980         
981         /* error checking */
982         if (ELEM3(NULL, gpd, gpl, gpf))
983                 return;
984                 
985         /* only convert if there are any strokes on this layer's frame to convert */
986         if (gpf->strokes.first == NULL)
987                 return;
988         
989         /* init the armature object (remove rotation and assign armature data to it) 
990          *      - must clear transforms set on object, as those skew our results
991          */
992         add_object_draw(OB_ARMATURE);
993         ob= OBACT;
994         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
995         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
996         arm= ob->data;
997         
998         /* rename object and armature to layer name */
999         rename_id((ID *)ob, gpl->info);
1000         rename_id((ID *)arm, gpl->info);
1001         
1002         /* this is editmode armature */
1003         arm->edbo= MEM_callocN(sizeof(ListBase), "arm edbo");
1004         
1005         /* convert segments to bones, strokes to bone chains */
1006         for (gps= gpf->strokes.first; gps; gps= gps->next) {
1007                 gp_stroke_to_bonechain(gpl, gps, arm, arm->edbo);
1008         }
1009         
1010         /* adjust roll of bones
1011          *      - set object as EditMode object, but need to clear afterwards!
1012          *      - use 'align to world z-up' option
1013          */
1014         {
1015                 /* set our data as if we're in editmode to fool auto_align_armature() */
1016                 scene->obedit= ob;
1017                 
1018                 /* WARNING: need to make sure this magic number doesn't change */
1019                 auto_align_armature(scene, v3d, 2);     
1020                 
1021                 scene->obedit= NULL;
1022         }
1023         
1024         /* flush editbones to armature */
1025         ED_armature_from_edit(scene, ob);
1026         ED_armature_edit_free(ob);
1027 }
1028
1029 /* --- */
1030
1031 /* convert grease-pencil strokes to another representation 
1032  *      mode:   1 - Active layer to path
1033  *                      2 - Active layer to bezier
1034  *                      3 - Active layer to armature
1035  */
1036 void gpencil_convert_operation (short mode)
1037 {
1038         Scene *scene= NULL; // XXX
1039         View3D *v3d= NULL; // XXX
1040         bGPdata *gpd;   
1041         float *fp= give_cursor(scene, v3d);
1042         
1043         /* get datablock to work on */
1044         gpd= gpencil_data_getactive(NULL);
1045         if (gpd == NULL) return;
1046         
1047         /* initialise 3d-cursor correction globals */
1048         initgrabz(v3d, fp[0], fp[1], fp[2]);
1049         
1050         /* handle selection modes */
1051         switch (mode) {
1052                 case 1: /* active layer only (to path) */
1053                 case 2: /* active layer only (to bezier) */
1054                 {
1055                         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
1056                         gp_layer_to_curve(gpd, gpl, scene, mode);
1057                 }
1058                         break;
1059                 case 3: /* active layer only (to armature) */
1060                 {
1061                         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
1062                         gp_layer_to_armature(gpd, gpl, scene, v3d, mode);
1063                 }
1064                         break;
1065         }
1066         
1067         /* redraw and undo-push */
1068         BIF_undo_push("GPencil Convert");
1069 }
1070
1071 /* display a menu for converting grease-pencil strokes */
1072 void gpencil_convert_menu (void)
1073 {
1074         bGPdata *gpd= gpencil_data_getactive(NULL);
1075         short mode;
1076         
1077         /* only show menu if it will be relevant */
1078         if (gpd == NULL) return;
1079         
1080         mode= pupmenu("Grease Pencil Convert %t|Active Layer To Path%x1|Active Layer to Bezier%x2|Active Layer to Armature%x3");
1081         if (mode <= 0) return;
1082         
1083         gpencil_convert_operation(mode);
1084 }
1085
1086 /* ************************************************** */
1087 /* GREASE-PENCIL EDITING MODE - Painting */
1088
1089 /* ---------- 'Globals' and Defines ----------------- */
1090
1091 /* maximum sizes of gp-session buffer */
1092 #define GP_STROKE_BUFFER_MAX    5000
1093
1094 /* Macros for accessing sensitivity thresholds... */
1095         /* minimum number of pixels mouse should move before new point created */
1096 #define MIN_MANHATTEN_PX        (U.gp_manhattendist)
1097         /* minimum length of new segment before new point can be added */
1098 #define MIN_EUCLIDEAN_PX        (U.gp_euclideandist)
1099
1100 /* macro to test if only converting endpoints - only for use when converting!  */       
1101 #define GP_BUFFER2STROKE_ENDPOINTS ((gpd->flag & GP_DATA_EDITPAINT) && (ctrl))
1102         
1103 /* ------ */
1104
1105 /* Temporary 'Stroke' Operation data */
1106 typedef struct tGPsdata {
1107         Scene *scene;       /* current scene from context */
1108         ScrArea *sa;            /* area where painting originated */
1109         ARegion *ar;        /* region where painting originated */
1110         View2D *v2d;            /* needed for GP_STROKE_2DSPACE */
1111         
1112         ImBuf *ibuf;            /* needed for GP_STROKE_2DIMAGE */
1113         struct IBufViewSettings {
1114                 int offsx, offsy;                       /* offsets */
1115                 int sizex, sizey;                       /* dimensions to use as scale-factor */
1116         } im2d_settings;        /* needed for GP_STROKE_2DIMAGE */
1117         
1118         bGPdata *gpd;           /* gp-datablock layer comes from */
1119         bGPDlayer *gpl;         /* layer we're working on */
1120         bGPDframe *gpf;         /* frame we're working on */
1121         
1122         short status;           /* current status of painting */
1123         short paintmode;        /* mode for painting */
1124         
1125         short mval[2];          /* current mouse-position */
1126         short mvalo[2];         /* previous recorded mouse-position */
1127         
1128         float pressure;         /* current stylus pressure */
1129         float opressure;        /* previous stylus pressure */
1130         
1131         short radius;           /* radius of influence for eraser */
1132 } tGPsdata;
1133
1134 /* values for tGPsdata->status */
1135 enum {
1136         GP_STATUS_NORMAL = 0,   /* running normally */
1137         GP_STATUS_ERROR,                /* something wasn't correctly set up */
1138         GP_STATUS_DONE                  /* painting done */
1139 };
1140
1141 /* values for tGPsdata->paintmode */
1142 enum {
1143         GP_PAINTMODE_DRAW = 0,
1144         GP_PAINTMODE_ERASER
1145 };
1146
1147 /* Return flags for adding points to stroke buffer */
1148 enum {
1149         GP_STROKEADD_INVALID    = -2,           /* error occurred - insufficient info to do so */
1150         GP_STROKEADD_OVERFLOW   = -1,           /* error occurred - cannot fit any more points */
1151         GP_STROKEADD_NORMAL,                            /* point was successfully added */
1152         GP_STROKEADD_FULL                                       /* cannot add any more points to buffer */
1153 };
1154
1155 /* ---------- Stroke Editing ------------ */
1156
1157 /* clear the session buffers (call this before AND after a paint operation) */
1158 static void gp_session_validatebuffer (tGPsdata *p)
1159 {
1160         bGPdata *gpd= p->gpd;
1161         
1162         /* clear memory of buffer (or allocate it if starting a new session) */
1163         if (gpd->sbuffer)
1164                 memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
1165         else
1166                 gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
1167         
1168         /* reset indices */
1169         gpd->sbuffer_size = 0;
1170         
1171         /* reset flags */
1172         gpd->sbuffer_sflag= 0;
1173 }
1174
1175 /* check if the current mouse position is suitable for adding a new point */
1176 static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2])
1177 {
1178         short dx= abs(mval[0] - pmval[0]);
1179         short dy= abs(mval[1] - pmval[1]);
1180         
1181         /* check if mouse moved at least certain distance on both axes (best case) */
1182         if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
1183                 return 1;
1184         
1185         /* check if the distance since the last point is significant enough */
1186         // future optimisation: sqrt here may be too slow?
1187         else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX)
1188                 return 1;
1189         
1190         /* mouse 'didn't move' */
1191         else
1192                 return 0;
1193 }
1194
1195 /* convert screen-coordinates to buffer-coordinates */
1196 static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
1197 {
1198         View3D *v3d= NULL; // XXX
1199         bGPdata *gpd= p->gpd;
1200         
1201         /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
1202         if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
1203                 const short mx=mval[0], my=mval[1];
1204                 float *fp= give_cursor(p->scene, NULL); // XXX NULL could be v3d
1205                 float dvec[3];
1206                 
1207                 /* Current method just converts each point in screen-coordinates to 
1208                  * 3D-coordinates using the 3D-cursor as reference. In general, this 
1209                  * works OK, but it could of course be improved.
1210                  *
1211                  * TODO:
1212                  *      - investigate using nearest point(s) on a previous stroke as
1213                  *        reference point instead or as offset, for easier stroke matching
1214                  *      - investigate projection onto geometry (ala retopo)
1215                  */
1216                 
1217                 /* method taken from editview.c - mouse_cursor() */
1218                 project_short_noclip(p->ar, v3d, fp, mval);
1219                 window_to_3d(p->ar, v3d, dvec, mval[0]-mx, mval[1]-my);
1220                 VecSubf(out, fp, dvec);
1221         }
1222         
1223         /* 2d - on 'canvas' (assume that p->v2d is set) */
1224         else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
1225                 float x, y;
1226                 
1227                 UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &x, &y);
1228                 
1229                 out[0]= x;
1230                 out[1]= y;
1231         }
1232         
1233         /* 2d - on image 'canvas' (assume that p->v2d is set) */
1234         else if (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) {
1235                 int sizex, sizey, offsx, offsy;
1236                 
1237                 /* get stored settings 
1238                  *      - assume that these have been set already (there are checks that set sane 'defaults' just in case)
1239                  */
1240                 sizex= p->im2d_settings.sizex;
1241                 sizey= p->im2d_settings.sizey;
1242                 offsx= p->im2d_settings.offsx;
1243                 offsy= p->im2d_settings.offsy;
1244                 
1245                 /* calculate new points */
1246                 out[0]= (float)(mval[0] - offsx) / (float)sizex;
1247                 out[1]= (float)(mval[1] - offsy) / (float)sizey;
1248         }
1249         
1250         /* 2d - relative to screen (viewport area) */
1251         else {
1252                 out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
1253                 out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
1254         }
1255 }
1256
1257 /* add current stroke-point to buffer (returns whether point was successfully added) */
1258 static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
1259 {
1260         bGPdata *gpd= p->gpd;
1261         tGPspoint *pt;
1262         
1263         /* check if still room in buffer */
1264         if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
1265                 return GP_STROKEADD_OVERFLOW;
1266         
1267         /* get pointer to destination point */
1268         pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
1269         
1270         /* store settings */
1271         pt->x= mval[0];
1272         pt->y= mval[1];
1273         pt->pressure= pressure;
1274         
1275         /* increment counters */
1276         gpd->sbuffer_size++;
1277         
1278         /* check if another operation can still occur */
1279         if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
1280                 return GP_STROKEADD_FULL;
1281         else
1282                 return GP_STROKEADD_NORMAL;
1283 }
1284
1285 /* smooth a stroke (in buffer) before storing it */
1286 static void gp_stroke_smooth (tGPsdata *p)
1287 {
1288         bGPdata *gpd= p->gpd;
1289         int i=0, cmx=gpd->sbuffer_size;
1290         int ctrl= 0; // XXX
1291         
1292         /* only smooth if smoothing is enabled, and we're not doing a straight line */
1293         if (!(U.gp_settings & GP_PAINT_DOSMOOTH) || GP_BUFFER2STROKE_ENDPOINTS)
1294                 return;
1295         
1296         /* don't try if less than 2 points in buffer */
1297         if ((cmx <= 2) || (gpd->sbuffer == NULL))
1298                 return;
1299         
1300         /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
1301         for (i=0; i < gpd->sbuffer_size; i++) {
1302                 tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
1303                 tGPspoint *pb= (i-1 > 0)?(pc-1):(pc);
1304                 tGPspoint *pa= (i-2 > 0)?(pc-2):(pb);
1305                 tGPspoint *pd= (i+1 < cmx)?(pc+1):(pc);
1306                 tGPspoint *pe= (i+2 < cmx)?(pc+2):(pd);
1307                 
1308                 pc->x= (short)(0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
1309                 pc->y= (short)(0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
1310         }
1311 }
1312
1313 /* simplify a stroke (in buffer) before storing it 
1314  *      - applies a reverse Chaikin filter
1315  *      - code adapted from etch-a-ton branch (editarmature_sketch.c)
1316  */
1317 static void gp_stroke_simplify (tGPsdata *p)
1318 {
1319         bGPdata *gpd= p->gpd;
1320         tGPspoint *old_points= (tGPspoint *)gpd->sbuffer;
1321         short num_points= gpd->sbuffer_size;
1322         short flag= gpd->sbuffer_sflag;
1323         short i, j;
1324         int ctrl= 0; // XXX
1325         
1326         /* only simplify if simlification is enabled, and we're not doing a straight line */
1327         if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || GP_BUFFER2STROKE_ENDPOINTS)
1328                 return;
1329         
1330         /* don't simplify if less than 4 points in buffer */
1331         if ((num_points <= 2) || (old_points == NULL))
1332                 return;
1333                 
1334         /* clear buffer (but don't free mem yet) so that we can write to it 
1335          *      - firstly set sbuffer to NULL, so a new one is allocated
1336          *      - secondly, reset flag after, as it gets cleared auto
1337          */
1338         gpd->sbuffer= NULL;
1339         gp_session_validatebuffer(p);
1340         gpd->sbuffer_sflag = flag;
1341         
1342 /* macro used in loop to get position of new point
1343  *      - used due to the mixture of datatypes in use here
1344  */
1345 #define GP_SIMPLIFY_AVPOINT(offs, sfac) \
1346         { \
1347                 co[0] += (float)(old_points[offs].x * sfac); \
1348                 co[1] += (float)(old_points[offs].y * sfac); \
1349                 pressure += old_points[offs].pressure * sfac; \
1350         }
1351         
1352         for (i = 0, j = 0; i < num_points; i++)
1353         {
1354                 if (i - j == 3)
1355                 {
1356                         float co[2], pressure;
1357                         short mco[2];
1358                         
1359                         /* initialise values */
1360                         co[0]= 0;
1361                         co[1]= 0;
1362                         pressure = 0;
1363                         
1364                         /* using macro, calculate new point */
1365                         GP_SIMPLIFY_AVPOINT(j, -0.25f);
1366                         GP_SIMPLIFY_AVPOINT(j+1, 0.75f);
1367                         GP_SIMPLIFY_AVPOINT(j+2, 0.75f);
1368                         GP_SIMPLIFY_AVPOINT(j+3, -0.25f);
1369                         
1370                         /* set values for adding */
1371                         mco[0]= (short)co[0];
1372                         mco[1]= (short)co[1];
1373                         
1374                         /* ignore return values on this... assume to be ok for now */
1375                         gp_stroke_addpoint(p, mco, pressure);
1376                         
1377                         j += 2;
1378                 }
1379         } 
1380         
1381         /* free old buffer */
1382         MEM_freeN(old_points);
1383 }
1384
1385
1386 /* make a new stroke from the buffer data */
1387 static void gp_stroke_newfrombuffer (tGPsdata *p)
1388 {
1389         bGPdata *gpd= p->gpd;
1390         bGPDstroke *gps;
1391         bGPDspoint *pt;
1392         tGPspoint *ptc;
1393         int i, totelem;
1394         int ctrl= 0; // XXX
1395         
1396         /* get total number of points to allocate space for:
1397          *      - in 'Draw Mode', holding the Ctrl-Modifier will only take endpoints
1398          *      - otherwise, do whole stroke
1399          */
1400         if (GP_BUFFER2STROKE_ENDPOINTS)
1401                 totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size;
1402         else
1403                 totelem = gpd->sbuffer_size;
1404         
1405         /* exit with error if no valid points from this stroke */
1406         if (totelem == 0) {
1407                 if (G.f & G_DEBUG) 
1408                         printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
1409                 return;
1410         }
1411         
1412         /* allocate memory for a new stroke */
1413         gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
1414         
1415         /* allocate enough memory for a continuous array for storage points */
1416         pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
1417         
1418         /* copy appropriate settings for stroke */
1419         gps->totpoints= totelem;
1420         gps->thickness= p->gpl->thickness;
1421         gps->flag= gpd->sbuffer_sflag;
1422         
1423         /* copy points from the buffer to the stroke */
1424         if (GP_BUFFER2STROKE_ENDPOINTS) {
1425                 /* 'Draw Mode' + Ctrl-Modifier - only endpoints */
1426                 {
1427                         /* first point */
1428                         ptc= gpd->sbuffer;
1429                         
1430                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1431                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1432                         
1433                         /* copy pressure */
1434                         pt->pressure= ptc->pressure;
1435                         
1436                         pt++;
1437                 }
1438                         
1439                 if (totelem == 2) {
1440                         /* last point if applicable */
1441                         ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
1442                         
1443                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1444                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1445                         
1446                         /* copy pressure */
1447                         pt->pressure= ptc->pressure;
1448                 }
1449         }
1450         else {
1451                 /* convert all points (normal behaviour) */
1452                 for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
1453                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1454                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1455                         
1456                         /* copy pressure */
1457                         pt->pressure= ptc->pressure;
1458                         
1459                         pt++;
1460                 }
1461         }
1462         
1463         /* add stroke to frame */
1464         BLI_addtail(&p->gpf->strokes, gps);
1465 }
1466
1467 /* --- 'Eraser' for 'Paint' Tool ------ */
1468
1469 /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
1470 static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
1471 {
1472         bGPDspoint *pt_tmp= gps->points;
1473         bGPDstroke *gsn = NULL;
1474
1475         /* if stroke only had two points, get rid of stroke */
1476         if (gps->totpoints == 2) {
1477                 /* free stroke points, then stroke */
1478                 MEM_freeN(pt_tmp);
1479                 BLI_freelinkN(&gpf->strokes, gps);
1480                 
1481                 /* nothing left in stroke, so stop */
1482                 return 1;
1483         }
1484
1485         /* if last segment, just remove segment from the stroke */
1486         else if (i == gps->totpoints - 2) {
1487                 /* allocate new points array, and assign most of the old stroke there */
1488                 gps->totpoints--;
1489                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1490                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
1491                 
1492                 /* free temp buffer */
1493                 MEM_freeN(pt_tmp);
1494                 
1495                 /* nothing left in stroke, so stop */
1496                 return 1;
1497         }
1498
1499         /* if first segment, just remove segment from the stroke */
1500         else if (i == 0) {
1501                 /* allocate new points array, and assign most of the old stroke there */
1502                 gps->totpoints--;
1503                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1504                 memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
1505                 
1506                 /* free temp buffer */
1507                 MEM_freeN(pt_tmp);
1508                 
1509                 /* no break here, as there might still be stuff to remove in this stroke */
1510                 return 0;
1511         }
1512
1513         /* segment occurs in 'middle' of stroke, so split */
1514         else {
1515                 /* duplicate stroke, and assign 'later' data to that stroke */
1516                 gsn= MEM_dupallocN(gps);
1517                 gsn->prev= gsn->next= NULL;
1518                 BLI_insertlinkafter(&gpf->strokes, gps, gsn);
1519                 
1520                 gsn->totpoints= gps->totpoints - i;
1521                 gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
1522                 memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
1523                 
1524                 /* adjust existing stroke  */
1525                 gps->totpoints= i;
1526                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1527                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
1528                 
1529                 /* free temp buffer */
1530                 MEM_freeN(pt_tmp);
1531                 
1532                 /* nothing left in stroke, so stop */
1533                 return 1;
1534         }
1535 }
1536
1537 /* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
1538 static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1)
1539 {
1540         /* simple within-radius check for now */
1541         if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
1542                 return 1;
1543         
1544         /* not inside */
1545         return 0;
1546
1547
1548 /* eraser tool - evaluation per stroke */
1549 static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
1550 {
1551         bGPDspoint *pt1, *pt2;
1552         View3D *v3d= NULL;
1553         int x0=0, y0=0, x1=0, y1=0;
1554         short xyval[2];
1555         int i;
1556         
1557         if (gps->totpoints == 0) {
1558                 /* just free stroke */
1559                 if (gps->points) 
1560                         MEM_freeN(gps->points);
1561                 BLI_freelinkN(&gpf->strokes, gps);
1562         }
1563         else if (gps->totpoints == 1) {
1564                 /* get coordinates */
1565                 if (gps->flag & GP_STROKE_3DSPACE) {
1566                         project_short(p->ar, v3d, &gps->points->x, xyval);
1567                         x0= xyval[0];
1568                         y0= xyval[1];
1569                 }
1570                 else if (gps->flag & GP_STROKE_2DSPACE) {                       
1571                         UI_view2d_view_to_region(p->v2d, gps->points->x, gps->points->y, &x0, &y0);
1572                 }
1573                 else if (gps->flag & GP_STROKE_2DIMAGE) {                       
1574                         int offsx, offsy, sizex, sizey;
1575                         
1576                         /* get stored settings */
1577                         sizex= p->im2d_settings.sizex;
1578                         sizey= p->im2d_settings.sizey;
1579                         offsx= p->im2d_settings.offsx;
1580                         offsy= p->im2d_settings.offsy;
1581                         
1582                         /* calculate new points */
1583                         x0= (short)((gps->points->x * sizex) + offsx);
1584                         y0= (short)((gps->points->y * sizey) + offsy);
1585                 }
1586                 else {
1587                         x0= (short)(gps->points->x / 1000 * p->sa->winx);
1588                         y0= (short)(gps->points->y / 1000 * p->sa->winy);
1589                 }
1590                 
1591                 /* do boundbox check first */
1592                 if (BLI_in_rcti(rect, x0, y0)) {
1593                         /* only check if point is inside */
1594                         if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) {
1595                                 /* free stroke */
1596                                 MEM_freeN(gps->points);
1597                                 BLI_freelinkN(&gpf->strokes, gps);
1598                         }
1599                 }
1600         }
1601         else {  
1602                 /* loop over the points in the stroke, checking for intersections 
1603                  *      - an intersection will require the stroke to be split
1604                  */
1605                 for (i=0; (i+1) < gps->totpoints; i++) {
1606                         /* get points to work with */
1607                         pt1= gps->points + i;
1608                         pt2= gps->points + i + 1;
1609                         
1610                         /* get coordinates */
1611                         if (gps->flag & GP_STROKE_3DSPACE) {
1612                                 project_short(p->ar, v3d, &pt1->x, xyval);
1613                                 x0= xyval[0];
1614                                 y0= xyval[1];
1615                                 
1616                                 project_short(p->ar, v3d, &pt2->x, xyval);
1617                                 x1= xyval[0];
1618                                 y1= xyval[1];
1619                         }
1620                         else if (gps->flag & GP_STROKE_2DSPACE) {
1621                                 UI_view2d_view_to_region(p->v2d, pt1->x, pt1->y, &x0, &y0);
1622                                 
1623                                 UI_view2d_view_to_region(p->v2d, pt2->x, pt2->y, &x1, &y1);
1624                         }
1625                         else if (gps->flag & GP_STROKE_2DIMAGE) {
1626                                 int offsx, offsy, sizex, sizey;
1627                                 
1628                                 /* get stored settings */
1629                                 sizex= p->im2d_settings.sizex;
1630                                 sizey= p->im2d_settings.sizey;
1631                                 offsx= p->im2d_settings.offsx;
1632                                 offsy= p->im2d_settings.offsy;
1633                                 
1634                                 /* calculate new points */
1635                                 x0= (short)((pt1->x * sizex) + offsx);
1636                                 y0= (short)((pt1->y * sizey) + offsy);
1637                                 
1638                                 x1= (short)((pt2->x * sizex) + offsx);
1639                                 y1= (short)((pt2->y * sizey) + offsy);
1640                         }
1641                         else {
1642                                 x0= (short)(pt1->x / 1000 * p->sa->winx);
1643                                 y0= (short)(pt1->y / 1000 * p->sa->winy);
1644                                 x1= (short)(pt2->x / 1000 * p->sa->winx);
1645                                 y1= (short)(pt2->y / 1000 * p->sa->winy);
1646                         }
1647                         
1648                         /* check that point segment of the boundbox of the eraser stroke */
1649                         if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
1650                                 /* check if point segment of stroke had anything to do with
1651                                  * eraser region  (either within stroke painted, or on its lines)
1652                                  *      - this assumes that linewidth is irrelevant
1653                                  */
1654                                 if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
1655                                         /* if function returns true, break this loop (as no more point to check) */
1656                                         if (gp_stroke_eraser_splitdel(gpf, gps, i))
1657                                                 break;
1658                                 }
1659                         }
1660                 }
1661         }
1662 }
1663
1664 /* erase strokes which fall under the eraser strokes */
1665 static void gp_stroke_doeraser (tGPsdata *p)
1666 {
1667         bGPDframe *gpf= p->gpf;
1668         bGPDstroke *gps, *gpn;
1669         rcti rect;
1670         
1671         /* rect is rectangle of eraser */
1672         rect.xmin= p->mval[0] - p->radius;
1673         rect.ymin= p->mval[1] - p->radius;
1674         rect.xmax= p->mval[0] + p->radius;
1675         rect.ymax= p->mval[1] + p->radius;
1676         
1677         /* loop over strokes, checking segments for intersections */
1678         for (gps= gpf->strokes.first; gps; gps= gpn) {
1679                 gpn= gps->next;
1680                 gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
1681         }
1682 }
1683
1684 /* ---------- 'Paint' Tool ------------ */
1685
1686 /* init new painting session */
1687 static void gp_session_initpaint (bContext *C, tGPsdata *p)
1688 {
1689         ScrArea *curarea= CTX_wm_area(C);
1690         ARegion *ar= CTX_wm_region(C);
1691         
1692         /* clear previous data (note: is on stack) */
1693         memset(p, 0, sizeof(tGPsdata));
1694         
1695         /* make sure the active view (at the starting time) is a 3d-view */
1696         if (curarea == NULL) {
1697                 p->status= GP_STATUS_ERROR;
1698                 if (G.f & G_DEBUG) 
1699                         printf("Error: No active view for painting \n");
1700                 return;
1701         }
1702         
1703         /* pass on current scene */
1704         p->scene= CTX_data_scene(C);
1705         
1706         switch (curarea->spacetype) {
1707                 /* supported views first */
1708                 case SPACE_VIEW3D:
1709                 {
1710                         View3D *v3d= curarea->spacedata.first;
1711                         
1712                         /* set current area */
1713                         p->sa= curarea;
1714                         p->ar= ar;
1715                         
1716                         /* check that gpencil data is allowed to be drawn */
1717                         if ((v3d->flag2 & V3D_DISPGP)==0) {
1718                                 p->status= GP_STATUS_ERROR;
1719                                 if (G.f & G_DEBUG) 
1720                                         printf("Error: In active view, Grease Pencil not shown \n");
1721                                 return;
1722                         }
1723                 }
1724                         break;
1725                 case SPACE_NODE:
1726                 {
1727                         SpaceNode *snode= curarea->spacedata.first;
1728                         
1729                         /* set current area */
1730                         p->sa= curarea;
1731                         p->ar= ar;
1732                         p->v2d= &ar->v2d;
1733                         
1734                         /* check that gpencil data is allowed to be drawn */
1735                         if ((snode->flag & SNODE_DISPGP)==0) {
1736                                 p->status= GP_STATUS_ERROR;
1737                                 if (G.f & G_DEBUG) 
1738                                         printf("Error: In active view, Grease Pencil not shown \n");
1739                                 return;
1740                         }
1741                 }
1742                         break;
1743                 case SPACE_SEQ:
1744                 {
1745                         SpaceSeq *sseq= curarea->spacedata.first;
1746                         
1747                         /* set current area */
1748                         p->sa= curarea;
1749                         p->ar= ar;
1750                         p->v2d= &ar->v2d;
1751                         
1752                         /* check that gpencil data is allowed to be drawn */
1753                         if (sseq->mainb == 0) {
1754                                 p->status= GP_STATUS_ERROR;
1755                                 if (G.f & G_DEBUG) 
1756                                         printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil \n");
1757                                 return;
1758                         }
1759                         if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
1760                                 p->status= GP_STATUS_ERROR;
1761                                 if (G.f & G_DEBUG) 
1762                                         printf("Error: In active view, Grease Pencil not shown \n");
1763                                 return;
1764                         }
1765                 }
1766                         break;  
1767                 case SPACE_IMAGE:
1768                 {
1769                         SpaceImage *sima= curarea->spacedata.first;
1770                         
1771                         /* set the current area */
1772                         p->sa= curarea;
1773                         p->ar= ar;
1774                         p->v2d= &ar->v2d;
1775                         p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1776                         
1777                         /* check that gpencil data is allowed to be drawn */
1778                         if ((sima->flag & SI_DISPGP)==0) {
1779                                 p->status= GP_STATUS_ERROR;
1780                                 if (G.f & G_DEBUG)
1781                                         printf("Error: In active view, Grease Pencil not shown \n");
1782                                 return;
1783                         }
1784                 }
1785                         break;
1786                 /* unsupported views */
1787                 default:
1788                 {
1789                         p->status= GP_STATUS_ERROR;
1790                         if (G.f & G_DEBUG) 
1791                                 printf("Error: Active view not appropriate for Grease Pencil drawing \n");
1792                         return;
1793                 }
1794                         break;
1795         }
1796         
1797         /* get gp-data */
1798         p->gpd= gpencil_data_getactive(p->sa);
1799         if (p->gpd == NULL) {
1800                 short ok;
1801                 
1802                 p->gpd= gpencil_data_addnew();
1803                 ok= gpencil_data_setactive(p->sa, p->gpd);
1804                 
1805                 /* most of the time, the following check isn't needed */
1806                 if (ok == 0) {
1807                         /* free gpencil data as it can't be used */
1808                         free_gpencil_data(p->gpd);
1809                         p->gpd= NULL;
1810                         p->status= GP_STATUS_ERROR;
1811                         if (G.f & G_DEBUG) 
1812                                 printf("Error: Could not assign newly created Grease Pencil data to active area \n");
1813                         return;
1814                 }
1815         }
1816         
1817         /* set edit flags */
1818         G.f |= G_GREASEPENCIL;
1819         
1820         /* clear out buffer (stored in gp-data) in case something contaminated it */
1821         gp_session_validatebuffer(p);
1822         
1823         /* set 'default' im2d_settings just in case something that uses this doesn't set it */
1824         p->im2d_settings.sizex= 1;
1825         p->im2d_settings.sizey= 1;
1826 }
1827
1828 /* cleanup after a painting session */
1829 static void gp_session_cleanup (tGPsdata *p)
1830 {
1831         bGPdata *gpd= p->gpd;
1832         
1833         /* error checking */
1834         if (gpd == NULL)
1835                 return;
1836         
1837         /* free stroke buffer */
1838         if (gpd->sbuffer) {
1839                 MEM_freeN(gpd->sbuffer);
1840                 gpd->sbuffer= NULL;
1841         }
1842         
1843         /* clear flags */
1844         gpd->sbuffer_size= 0;
1845         gpd->sbuffer_sflag= 0;
1846 }
1847
1848 /* init new stroke */
1849 static void gp_paint_initstroke (tGPsdata *p, short paintmode)
1850 {       
1851         /* get active layer (or add a new one if non-existent) */
1852         p->gpl= gpencil_layer_getactive(p->gpd);
1853         if (p->gpl == NULL)
1854                 p->gpl= gpencil_layer_addnew(p->gpd);
1855         if (p->gpl->flag & GP_LAYER_LOCKED) {
1856                 p->status= GP_STATUS_ERROR;
1857                 if (G.f & G_DEBUG)
1858                         printf("Error: Cannot paint on locked layer \n");
1859                 return;
1860         }
1861                 
1862         /* get active frame (add a new one if not matching frame) */
1863         p->gpf= gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1);
1864         if (p->gpf == NULL) {
1865                 p->status= GP_STATUS_ERROR;
1866                 if (G.f & G_DEBUG) 
1867                         printf("Error: No frame created (gpencil_paint_init) \n");
1868                 return;
1869         }
1870         else
1871                 p->gpf->flag |= GP_FRAME_PAINT;
1872         
1873         /* set 'eraser' for this stroke if using eraser */
1874         p->paintmode= paintmode;
1875         if (p->paintmode == GP_PAINTMODE_ERASER)
1876                 p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
1877         
1878         /* check if points will need to be made in view-aligned space */
1879         if (p->gpd->flag & GP_DATA_VIEWALIGN) {
1880                 switch (p->sa->spacetype) {
1881                         case SPACE_VIEW3D:
1882                         {
1883                                 View3D *v3d= (View3D *)p->sa->spacedata.first;
1884                                 float *fp= give_cursor(p->scene, v3d);
1885                                 initgrabz(v3d, fp[0], fp[1], fp[2]);
1886                                 
1887                                 p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
1888                         }
1889                                 break;
1890                         case SPACE_NODE:
1891                         {
1892                                 p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1893                         }
1894                                 break;
1895                         case SPACE_SEQ:
1896                         {
1897                                 SpaceSeq *sseq= (SpaceSeq *)p->sa->spacedata.first;
1898                                 int rectx, recty;
1899                                 float zoom, zoomx, zoomy;
1900                                 
1901                                 /* set draw 2d-stroke flag */
1902                                 p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1903                                 
1904                                 /* calculate zoom factor */
1905                                 zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom));
1906                                 if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
1907                                         zoomx = zoom * ((float)p->scene->r.xasp / (float)p->scene->r.yasp);
1908                                         zoomy = zoom;
1909                                 } 
1910                                 else
1911                                         zoomx = zoomy = zoom;
1912                                 
1913                                 /* calculate rect size to use to calculate the size of the drawing area
1914                                  *      - We use the size of the output image not the size of the ibuf being shown
1915                                  *        as it is too messy getting the ibuf (and could be too slow). This should be
1916                                  *        a reasonable for most cases anyway.
1917                                  */
1918                                 rectx= (p->scene->r.size * p->scene->r.xsch) / 100;
1919                                 recty= (p->scene->r.size * p->scene->r.ysch) / 100; 
1920                                 
1921                                 /* set offset and scale values for opertations to use */
1922                                 p->im2d_settings.sizex= (int)(zoomx * rectx);
1923                                 p->im2d_settings.sizey= (int)(zoomy * recty);
1924                                 p->im2d_settings.offsx= (int)((p->sa->winx-p->im2d_settings.sizex)/2 + sseq->xof);
1925                                 p->im2d_settings.offsy= (int)((p->sa->winy-p->im2d_settings.sizey)/2 + sseq->yof);
1926                         }
1927                                 break;
1928                         case SPACE_IMAGE:
1929                         {
1930                                 /* check if any ibuf available */
1931                                 if (p->ibuf)
1932                                         p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1933                         }
1934                                 break;
1935                 }
1936         }
1937 }
1938
1939 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1940 static void gp_paint_strokeend (tGPsdata *p)
1941 {
1942         /* check if doing eraser or not */
1943         if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
1944                 /* smooth stroke before transferring? */
1945                 gp_stroke_smooth(p);
1946                 
1947                 /* simplify stroke before transferring? */
1948                 gp_stroke_simplify(p);
1949                 
1950                 /* transfer stroke to frame */
1951                 gp_stroke_newfrombuffer(p);
1952         }
1953         
1954         /* clean up buffer now */
1955         gp_session_validatebuffer(p);
1956 }
1957
1958 /* finish off stroke painting operation */
1959 static void gp_paint_cleanup (tGPsdata *p)
1960 {
1961         /* finish off a stroke */
1962         gp_paint_strokeend(p);
1963         
1964         /* "unlock" frame */
1965         p->gpf->flag &= ~GP_FRAME_PAINT;
1966         
1967         /* add undo-push so stroke can be undone */
1968         /* FIXME: currently disabled, as it's impossible to get this working nice
1969          * as gpenci data is on currently screen-level (which isn't saved to undo files)
1970          */
1971         //BIF_undo_push("GPencil Stroke");
1972         
1973         /* force redraw after drawing action */
1974         // XXX force_draw_plus(SPACE_ACTION, 0);
1975 }
1976
1977 /* -------- */
1978
1979 /* main call to paint a new stroke */
1980 // XXX will become modal(), gets event, includes all info!
1981 short gpencil_paint (bContext *C, short paintmode)
1982 {
1983         tGPsdata p;
1984         short ok = GP_STROKEADD_NORMAL;
1985         
1986         /* init paint-data */
1987         gp_session_initpaint(C, &p);
1988         if (p.status == GP_STATUS_ERROR) {
1989                 gp_session_cleanup(&p);
1990                 return 0;
1991         }
1992         gp_paint_initstroke(&p, paintmode);
1993         if (p.status == GP_STATUS_ERROR) {
1994                 gp_session_cleanup(&p);
1995                 return 0;
1996         }
1997         
1998         /* set cursor to indicate drawing */
1999         // XXX (cursor callbacks in regiontype) setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
2000         
2001         /* init drawing-device settings */
2002         // XXX getmouseco_areawin(p.mval);
2003         // XXX p.pressure = get_pressure();
2004         
2005         p.mvalo[0]= p.mval[0];
2006         p.mvalo[1]= p.mval[1];
2007         p.opressure= p.pressure;
2008         
2009         /* radius for eraser circle is defined in userprefs now */
2010         // TODO: make this more easily tweaked... 
2011         p.radius= U.gp_eraser;
2012         
2013         /* start drawing eraser-circle (if applicable) */
2014         //if (paintmode == GP_PAINTMODE_ERASER)
2015         // XXX  draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again
2016         
2017         /* only allow painting of single 'dots' if: 
2018          *      - pressure is not excessive (as it can be on some windows tablets)
2019          *      - draw-mode for active datablock is turned on
2020          *      - not erasing
2021          */
2022         if (paintmode != GP_PAINTMODE_ERASER) {
2023                 if (!(p.pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { 
2024                         gp_stroke_addpoint(&p, p.mval, p.pressure);
2025                 }
2026         }
2027         
2028         /* XXX paint loop */
2029         if(0) {
2030                 /* get current user input */
2031                 // XXX getmouseco_areawin(p.mval);
2032                 // XXX p.pressure = get_pressure();
2033                 
2034                 /* only add current point to buffer if mouse moved (otherwise wait until it does) */
2035                 if (paintmode == GP_PAINTMODE_ERASER) {
2036                         /* do 'live' erasing now */
2037                         gp_stroke_doeraser(&p);
2038                         
2039                         // XXX draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0);
2040                         // XXX force_draw(0);
2041                         
2042                         p.mvalo[0]= p.mval[0];
2043                         p.mvalo[1]= p.mval[1];
2044                         p.opressure= p.pressure;
2045                 }
2046                 else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) {
2047                         /* try to add point */
2048                         ok= gp_stroke_addpoint(&p, p.mval, p.pressure);
2049                         
2050                         /* handle errors while adding point */
2051                         if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
2052                                 /* finish off old stroke */
2053                                 gp_paint_strokeend(&p);
2054                                 
2055                                 /* start a new stroke, starting from previous point */
2056                                 gp_stroke_addpoint(&p, p.mvalo, p.opressure);
2057                                 ok= gp_stroke_addpoint(&p, p.mval, p.pressure);
2058                         }
2059                         else if (ok == GP_STROKEADD_INVALID) {
2060                                 /* the painting operation cannot continue... */
2061                                 error("Cannot paint stroke");
2062                                 p.status = GP_STATUS_ERROR;
2063                                 
2064                                 if (G.f & G_DEBUG) 
2065                                         printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
2066                                 // XXX break;
2067                         }
2068                         // XXX force_draw(0);
2069                         
2070                         p.mvalo[0]= p.mval[0];
2071                         p.mvalo[1]= p.mval[1];
2072                         p.opressure= p.pressure;
2073                 }
2074                 
2075                 /* do mouse checking at the end, so don't check twice, and potentially
2076                  * miss a short tap 
2077                  */
2078         }
2079         
2080         /* clear edit flags */
2081         G.f &= ~G_GREASEPENCIL;
2082         
2083         /* restore cursor to indicate end of drawing */
2084         // XXX  (cursor callbacks in regiontype) setcursor_space(p.sa->spacetype, CURSOR_STD);
2085         
2086         /* check size of buffer before cleanup, to determine if anything happened here */
2087         if (paintmode == GP_PAINTMODE_ERASER) {
2088                 ok= 1; /* assume that we did something... */
2089                 // XXX draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0);
2090         }
2091         else
2092                 ok= p.gpd->sbuffer_size;
2093         
2094         /* cleanup */
2095         gp_paint_cleanup(&p);
2096         gp_session_cleanup(&p);
2097         
2098         /* done! return if a stroke was successfully added */
2099         return ok;
2100 }
2101
2102
2103 /* All event (loops) handling checking if stroke drawing should be initiated
2104  * should call this function.
2105  */
2106 short gpencil_do_paint (bContext *C)
2107 {
2108         ScrArea *sa= CTX_wm_area(C);
2109         bGPdata *gpd = gpencil_data_getactive(sa);
2110         short retval= 0;
2111         int alt= 0, shift= 0, mbut= 0; // XXX
2112         
2113         /* check if possible to do painting */
2114         if (gpd == NULL) 
2115                 return 0;
2116         
2117         /* currently, we will only 'paint' if:
2118          *      1. draw-mode on gpd is set (for accessibility reasons)
2119          *              a) single dots are only available by this method if a single click is made
2120          *              b) a straight line is drawn if ctrl-modifier is held (check is done when stroke is converted!)
2121          *      2. if shift-modifier is held + lmb -> 'quick paint'
2122          *
2123          *      OR
2124          * 
2125          * draw eraser stroke if:
2126          *      1. using the eraser on a tablet
2127          *      2. draw-mode on gpd is set (for accessiblity reasons)
2128          *              (eraser is mapped to right-mouse)
2129          *      3. Alt + 'select' mouse-button
2130          *              i.e.  if LMB = select: Alt-LMB
2131          *                        if RMB = select: Alt-RMB
2132          */
2133         if (get_activedevice() == 2) {
2134                 /* eraser on a tablet - always try to erase strokes */
2135                 retval = gpencil_paint(C, GP_PAINTMODE_ERASER);
2136         }
2137         else if (gpd->flag & GP_DATA_EDITPAINT) {
2138                 /* try to paint/erase */
2139                 if (mbut == L_MOUSE)
2140                         retval = gpencil_paint(C, GP_PAINTMODE_DRAW);
2141                 else if (mbut == R_MOUSE)
2142                         retval = gpencil_paint(C, GP_PAINTMODE_ERASER);
2143         }
2144         else if (!(gpd->flag & GP_DATA_LMBPLOCK)) {
2145                 /* try to paint/erase as not locked */
2146                 if (shift && (mbut == L_MOUSE)) {
2147                         retval = gpencil_paint(C, GP_PAINTMODE_DRAW);
2148                 }
2149                 else if (alt) {
2150                         if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE))
2151                                 retval = gpencil_paint(C, GP_PAINTMODE_ERASER);
2152                         else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE))
2153                                 retval = gpencil_paint(C, GP_PAINTMODE_ERASER);
2154                 }
2155         }
2156         
2157         /* return result of trying to paint */
2158         return retval;
2159 }
2160
2161 /* ************************************************** */