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