9a2988e6e6d89744be3573c7d9849aa17c7f64e6
[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_editarmature.h"
71 #include "BIF_editview.h"
72 #include "BIF_graphics.h"
73 #include "BIF_interface.h"
74 #include "BIF_mywindow.h"
75 #include "BIF_resources.h"
76 #include "BIF_space.h"
77 #include "BIF_screen.h"
78 #include "BIF_toolbox.h"
79 #include "BIF_toets.h"
80
81 #include "BDR_gpencil.h"
82 #include "BIF_drawgpencil.h"
83
84 #include "BDR_editobject.h"
85
86 #include "BSE_drawipo.h"
87 #include "BSE_headerbuttons.h"
88 #include "BSE_view.h"
89
90 #include "blendef.h"
91
92 #include "PIL_time.h"                   /* sleep                                */
93 #include "mydevice.h"
94
95 /* ************************************************** */
96 /* GENERAL STUFF */
97
98 /* --------- Memory Management ------------ */
99
100 /* Free strokes belonging to a gp-frame */
101 void free_gpencil_strokes (bGPDframe *gpf)
102 {
103         bGPDstroke *gps, *gpsn;
104         
105         /* error checking */
106         if (gpf == NULL) return;
107         
108         /* free strokes */
109         for (gps= gpf->strokes.first; gps; gps= gpsn) {
110                 gpsn= gps->next;
111                 
112                 /* free stroke memory arrays, then stroke itself */
113                 MEM_freeN(gps->points);
114                 BLI_freelinkN(&gpf->strokes, gps);
115         }
116 }
117
118 /* Free all of a gp-layer's frames */
119 void free_gpencil_frames (bGPDlayer *gpl)
120 {
121         bGPDframe *gpf, *gpfn;
122         
123         /* error checking */
124         if (gpl == NULL) return;
125         
126         /* free frames */
127         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
128                 gpfn= gpf->next;
129                 
130                 /* free strokes and their associated memory */
131                 free_gpencil_strokes(gpf);
132                 BLI_freelinkN(&gpl->frames, gpf);
133         }
134 }
135
136 /* Free all of the gp-layers for a viewport (list should be &G.vd->gpd or so) */
137 void free_gpencil_layers (ListBase *list) 
138 {
139         bGPDlayer *gpl, *gpln;
140         
141         /* error checking */
142         if (list == NULL) return;
143         
144         /* delete layers*/
145         for (gpl= list->first; gpl; gpl= gpln) {
146                 gpln= gpl->next;
147                 
148                 /* free layers and their data */
149                 free_gpencil_frames(gpl);
150                 BLI_freelinkN(list, gpl);
151         }
152 }
153
154 /* Free gp-data and all it's related data */
155 void free_gpencil_data (bGPdata *gpd)
156 {
157         /* free layers then data itself */
158         free_gpencil_layers(&gpd->layers);
159         MEM_freeN(gpd);
160 }
161
162 /* -------- Container Creation ---------- */
163
164 /* add a new gp-frame to the given layer */
165 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
166 {
167         bGPDframe *gpf, *gf;
168         short state=0;
169         
170         /* error checking */
171         if ((gpl == NULL) || (cframe <= 0))
172                 return NULL;
173                 
174         /* allocate memory for this frame */
175         gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
176         gpf->framenum= cframe;
177         
178         /* find appropriate place to add frame */
179         if (gpl->frames.first) {
180                 for (gf= gpl->frames.first; gf; gf= gf->next) {
181                         /* check if frame matches one that is supposed to be added */
182                         if (gf->framenum == cframe) {
183                                 state= -1;
184                                 break;
185                         }
186                         
187                         /* if current frame has already exceeded the frame to add, add before */
188                         if (gf->framenum > cframe) {
189                                 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
190                                 state= 1;
191                                 break;
192                         }
193                 }
194         }
195         
196         /* check whether frame was added successfully */
197         if (state == -1) {
198                 MEM_freeN(gpf);
199                 printf("Error: frame (%d) existed already for this layer \n", cframe);
200         }
201         else if (state == 0) {
202                 /* add to end then! */
203                 BLI_addtail(&gpl->frames, gpf);
204         }
205         
206         /* return frame */
207         return gpf;
208 }
209
210 /* add a new gp-layer and make it the active layer */
211 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
212 {
213         bGPDlayer *gpl;
214         
215         /* check that list is ok */
216         if (gpd == NULL)
217                 return NULL;
218                 
219         /* allocate memory for frame and add to end of list */
220         gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
221         
222         /* add to datablock */
223         BLI_addtail(&gpd->layers, gpl);
224         
225         /* set basic settings */
226         gpl->color[3]= 1.0f;
227         gpl->thickness = 1;
228         
229         /* auto-name */
230         sprintf(gpl->info, "GP_Layer");
231         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
232         
233         /* make this one the active one */
234         gpencil_layer_setactive(gpd, gpl);
235         
236         /* return layer */
237         return gpl;
238 }
239
240 /* add a new gp-datablock */
241 bGPdata *gpencil_data_addnew (void)
242 {
243         bGPdata *gpd;
244         
245         /* allocate memory for a new block */
246         gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
247         
248         /* initial settings */
249                 /* it is quite useful to be able to see this info, so on by default */
250         gpd->flag = GP_DATA_DISPINFO;
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                 // FIXME: maybe we need to counterotate this for object rotation?
698                 VecCopyf(p3d, &pt->x);
699         }
700         else {
701                 short mval[2], mx, my;
702                 float *fp= give_cursor();
703                 float dvec[3];
704                 
705                 /* get screen coordinate */
706                 if (gps->flag & GP_STROKE_2DSPACE) {
707                         View2D *v2d= spacelink_get_view2d(curarea->spacedata.first);
708                         ipoco_to_areaco_noclip(v2d, &pt->x, mval);
709                 }
710                 else {
711                         mval[0]= (pt->x / 1000 * curarea->winx);
712                         mval[1]= (pt->y / 1000 * curarea->winy);
713                 }
714                 mx= mval[0]; 
715                 my= mval[1];
716                 
717                 /* convert screen coordinate to 3d coordinates 
718                  *      - method taken from editview.c - mouse_cursor() 
719                  */
720                 project_short_noclip(fp, mval);
721                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
722                 VecSubf(p3d, fp, dvec);
723         }
724 }
725
726 /* --- */
727
728 /* convert stroke to 3d path */
729 static void gp_stroke_to_path (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
730 {
731         bGPDspoint *pt;
732         Nurb *nu;
733         BPoint *bp;
734         int i;
735         
736         /* create new 'nurb' within the curve */
737         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
738         
739         nu->pntsu= gps->totpoints;
740         nu->pntsv= 1;
741         nu->orderu= gps->totpoints;
742         nu->flagu= 2;   /* endpoint */
743         nu->resolu= 32;
744         
745         nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
746         
747         /* add points */
748         for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
749                 float p3d[3];
750                 
751                 /* get coordinates to add at */
752                 gp_strokepoint_convertcoords(gps, pt, p3d);
753                 VecCopyf(bp->vec, p3d);
754                 
755                 /* set settings */
756                 bp->f1= SELECT;
757                 bp->radius = bp->weight = pt->pressure * gpl->thickness;
758         }
759         
760         /* add nurb to curve */
761         BLI_addtail(&cu->nurb, nu);
762 }
763
764 /* convert stroke to 3d bezier */
765 static void gp_stroke_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
766 {
767         bGPDspoint *pt;
768         Nurb *nu;
769         BezTriple *bezt;
770         int i;
771         
772         /* create new 'nurb' within the curve */
773         nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
774         
775         nu->pntsu= gps->totpoints;
776         nu->resolu= 12;
777         nu->resolv= 12;
778         nu->type= CU_BEZIER;
779         nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
780         
781         /* add points */
782         for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) {
783                 float p3d[3];
784                 
785                 /* get coordinates to add at */
786                 gp_strokepoint_convertcoords(gps, pt, p3d);
787                 
788                 /* TODO: maybe in future the handles shouldn't be in same place */
789                 VecCopyf(bezt->vec[0], p3d);
790                 VecCopyf(bezt->vec[1], p3d);
791                 VecCopyf(bezt->vec[2], p3d);
792                 
793                 /* set settings */
794                 bezt->h1= bezt->h2= HD_FREE;
795                 bezt->f1= bezt->f2= bezt->f3= SELECT;
796                 bezt->radius = bezt->weight = pt->pressure * gpl->thickness;
797         }
798         
799         /* must calculate handles or else we crash */
800         calchandlesNurb(nu);
801         
802         /* add nurb to curve */
803         BLI_addtail(&cu->nurb, nu);
804 }
805
806 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
807 static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl, short mode)
808 {
809         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
810         bGPDstroke *gps;
811         Object *ob;
812         Curve *cu;
813         
814         /* error checking */
815         if (ELEM3(NULL, gpd, gpl, gpf))
816                 return;
817                 
818         /* only convert if there are any strokes on this layer's frame to convert */
819         if (gpf->strokes.first == NULL)
820                 return;
821                 
822         /* initialise the curve */      
823         cu= add_curve(gpl->info, 1);
824         cu->flag |= CU_3D;
825         
826         /* init the curve object (remove rotation and assign curve data to it) */
827         add_object_draw(OB_CURVE);
828         ob= OBACT;
829         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
830         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
831         ob->data= cu;
832         
833         /* add points to curve */
834         for (gps= gpf->strokes.first; gps; gps= gps->next) {
835                 switch (mode) {
836                         case 1: 
837                                 gp_stroke_to_path(gpl, gps, cu);
838                                 break;
839                         case 2:
840                                 gp_stroke_to_bezier(gpl, gps, cu);
841                                 break;
842                 }
843         }
844 }
845
846 /* --- */
847
848 /* convert a stroke to a bone chain */
849 static void gp_stroke_to_bonechain (bGPDlayer *gpl, bGPDstroke *gps, bArmature *arm, ListBase *bones)
850 {
851         EditBone *ebo, *prev=NULL;
852         bGPDspoint *pt, *ptn;
853         int i;
854         
855         /* add each segment separately */
856         for (i=0, pt=gps->points, ptn=gps->points+1; i < (gps->totpoints-1); prev=ebo, i++, pt++, ptn++) {
857                 float p3da[3], p3db[3];
858                 
859                 /* get coordinates to add at */
860                 gp_strokepoint_convertcoords(gps, pt, p3da);
861                 gp_strokepoint_convertcoords(gps, ptn, p3db);
862                 
863                 /* allocate new bone */
864                 ebo= MEM_callocN(sizeof(EditBone), "eBone");
865                 
866                 VecCopyf(ebo->head, p3da);
867                 VecCopyf(ebo->tail, p3db);
868                 
869                 /* add new bone - note: sync with editarmature.c::add_editbone() */
870                 BLI_strncpy(ebo->name, "Stroke", 32);
871                 unique_editbone_name(bones, ebo->name);
872                 
873                 BLI_addtail(bones, ebo);
874                 
875                 ebo->flag |= BONE_CONNECTED;
876                 ebo->weight= 1.0F;
877                 ebo->dist= 0.25F;
878                 ebo->xwidth= 0.1;
879                 ebo->zwidth= 0.1;
880                 ebo->ease1= 1.0;
881                 ebo->ease2= 1.0;
882                 ebo->rad_head= pt->pressure * gpl->thickness * 0.1;
883                 ebo->rad_tail= ptn->pressure * gpl->thickness * 0.1;
884                 ebo->segments= 1;
885                 ebo->layer= arm->layer;
886                 
887                 /* set parenting */
888                 // TODO: also adjust roll....
889                 ebo->parent= prev;
890         }
891 }
892
893 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
894 static void gp_layer_to_armature (bGPdata *gpd, bGPDlayer *gpl, short mode)
895 {
896         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
897         bGPDstroke *gps;
898         Object *ob;
899         bArmature *arm;
900         ListBase bones = {0,0};
901         
902         /* error checking */
903         if (ELEM3(NULL, gpd, gpl, gpf))
904                 return;
905                 
906         /* only convert if there are any strokes on this layer's frame to convert */
907         if (gpf->strokes.first == NULL)
908                 return;
909                 
910         /* initialise the armature */   
911         arm= add_armature(gpl->info);
912         
913         /* init the armature object (remove rotation and assign armature data to it) */
914         add_object_draw(OB_ARMATURE);
915         ob= OBACT;
916         ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
917         ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
918         ob->data= arm;
919         
920         /* convert segments to bones, strokes to bone chains */
921         for (gps= gpf->strokes.first; gps; gps= gps->next) {
922                 gp_stroke_to_bonechain(gpl, gps, arm, &bones);
923         }
924         
925         /* flush editbones to armature */
926         editbones_to_armature(&bones, ob);
927         if (bones.first) BLI_freelistN(&bones);
928 }
929
930 /* --- */
931
932 /* convert grease-pencil strokes to another representation 
933  *      mode:   1 - Active layer to path
934  *                      2 - Active layer to bezier
935  *                      3 - Active layer to armature
936  */
937 void gpencil_convert_operation (short mode)
938 {
939         bGPdata *gpd;   
940         float *fp= give_cursor();
941         
942         /* get datablock to work on */
943         gpd= gpencil_data_getactive(NULL);
944         if (gpd == NULL) return;
945         
946         /* initialise 3d-cursor correction globals */
947         initgrabz(fp[0], fp[1], fp[2]);
948         
949         /* handle selection modes */
950         switch (mode) {
951                 case 1: /* active layer only (to path) */
952                 case 2: /* active layer only (to bezier) */
953                 {
954                         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
955                         gp_layer_to_curve(gpd, gpl, mode);
956                 }
957                         break;
958                 case 3: /* active layer only (to armature) */
959                 {
960                         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
961                         gp_layer_to_armature(gpd, gpl, mode);
962                 }
963                         break;
964         }
965         
966         /* redraw and undo-push */
967         BIF_undo_push("GPencil Convert");
968         allqueue(REDRAWVIEW3D, 0);
969         allqueue(REDRAWOOPS, 0);
970 }
971
972 /* display a menu for converting grease-pencil strokes */
973 void gpencil_convert_menu (void)
974 {
975         bGPdata *gpd= gpencil_data_getactive(NULL);
976         short mode;
977         
978         /* only show menu if it will be relevant */
979         if (gpd == NULL) return;
980         
981         mode= pupmenu("Grease Pencil Convert %t|Active Layer To Path%x1|Active Layer to Bezier%x2|Active Layer to Armature%x3");
982         if (mode <= 0) return;
983         
984         gpencil_convert_operation(mode);
985 }
986
987 /* ************************************************** */
988 /* GREASE-PENCIL EDITING MODE - Painting */
989
990 /* ---------- 'Globals' and Defines ----------------- */
991
992 /* maximum sizes of gp-session buffer */
993 #define GP_STROKE_BUFFER_MAX    5000
994
995 /* Hardcoded sensitivity thresholds... */
996 // TODO: one day, these might be added to the UI if it is necessary
997         /* minimum number of pixels mouse should move before new point created */
998 #define MIN_MANHATTEN_PX                3       
999         /* minimum length of new segment before new point can be added */
1000 #define MIN_EUCLIDEAN_PX                20
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' (asume that p->v2d is set) */
1250         else if ( (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) && 
1251                           (p->v2d) && (p->ibuf) ) 
1252         {
1253                 float x, y;
1254                 
1255                 /* convert to 'canvas' coordinates (not need to adjust to canvas) */
1256                 areamouseco_to_ipoco(p->v2d, mval, &x, &y);
1257                 
1258                 out[0]= x;
1259                 out[1]= y;
1260         }
1261         
1262         /* 2d - relative to screen (viewport area) */
1263         else {
1264                 out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
1265                 out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
1266         }
1267 }
1268
1269 /* add current stroke-point to buffer (returns whether point was successfully added) */
1270 static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
1271 {
1272         bGPdata *gpd= p->gpd;
1273         tGPspoint *pt;
1274         
1275         /* check if still room in buffer */
1276         if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
1277                 return GP_STROKEADD_OVERFLOW;
1278         
1279         /* get pointer to destination point */
1280         pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
1281         
1282         /* store settings */
1283         pt->x= mval[0];
1284         pt->y= mval[1];
1285         pt->pressure= pressure;
1286         
1287         /* increment counters */
1288         gpd->sbuffer_size++;
1289         
1290         /* check if another operation can still occur */
1291         if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
1292                 return GP_STROKEADD_FULL;
1293         else
1294                 return GP_STROKEADD_NORMAL;
1295 }
1296
1297 /* make a new stroke from the buffer data */
1298 static void gp_stroke_newfrombuffer (tGPsdata *p)
1299 {
1300         bGPdata *gpd= p->gpd;
1301         bGPDstroke *gps;
1302         bGPDspoint *pt;
1303         tGPspoint *ptc;
1304         int i, totelem;
1305
1306         /* macro to test if only converting endpoints  */       
1307         #define GP_BUFFER2STROKE_ENDPOINTS ((gpd->flag & GP_DATA_EDITPAINT) && (G.qual & LR_CTRLKEY))
1308         
1309         /* get total number of points to allocate space for:
1310          *      - in 'Draw Mode', holding the Ctrl-Modifier will only take endpoints
1311          *      - otherwise, do whole stroke
1312          */
1313         if (GP_BUFFER2STROKE_ENDPOINTS)
1314                 totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size;
1315         else
1316                 totelem = gpd->sbuffer_size;
1317         
1318         /* exit with error if no valid points from this stroke */
1319         if (totelem == 0) {
1320                 if (G.f & G_DEBUG) 
1321                         printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
1322                 return;
1323         }
1324         
1325         /* allocate memory for a new stroke */
1326         gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
1327         
1328         /* allocate enough memory for a continuous array for storage points */
1329         pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
1330         
1331         /* copy appropriate settings for stroke */
1332         gps->totpoints= totelem;
1333         gps->thickness= p->gpl->thickness;
1334         gps->flag= gpd->sbuffer_sflag;
1335         
1336         /* copy points from the buffer to the stroke */
1337         if (GP_BUFFER2STROKE_ENDPOINTS) {
1338                 /* 'Draw Mode' + Ctrl-Modifier - only endpoints */
1339                 {
1340                         /* first point */
1341                         ptc= gpd->sbuffer;
1342                         
1343                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1344                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1345                         
1346                         /* copy pressure */
1347                         pt->pressure= ptc->pressure;
1348                         
1349                         pt++;
1350                 }
1351                         
1352                 if (totelem == 2) {
1353                         /* last point if applicable */
1354                         ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
1355                         
1356                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1357                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1358                         
1359                         /* copy pressure */
1360                         pt->pressure= ptc->pressure;
1361                 }
1362         }
1363         else {
1364                 /* convert all points (normal behaviour) */
1365                 for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
1366                         /* convert screen-coordinates to appropriate coordinates (and store them) */
1367                         gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1368                         
1369                         /* copy pressure */
1370                         pt->pressure= ptc->pressure;
1371                         
1372                         pt++;
1373                 }
1374         }
1375         
1376         /* add stroke to frame */
1377         BLI_addtail(&p->gpf->strokes, gps);
1378         
1379         /* undefine macro to test if only converting endpoints  */      
1380         #undef GP_BUFFER2STROKE_ENDPOINTS
1381 }
1382
1383 /* --- 'Eraser' for 'Paint' Tool ------ */
1384
1385 /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
1386 static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
1387 {
1388         bGPDspoint *pt_tmp= gps->points;
1389         bGPDstroke *gsn = NULL;
1390
1391         /* if stroke only had two points, get rid of stroke */
1392         if (gps->totpoints == 2) {
1393                 /* free stroke points, then stroke */
1394                 MEM_freeN(pt_tmp);
1395                 BLI_freelinkN(&gpf->strokes, gps);
1396                 
1397                 /* nothing left in stroke, so stop */
1398                 return 1;
1399         }
1400
1401         /* if last segment, just remove segment from the stroke */
1402         else if (i == gps->totpoints - 2) {
1403                 /* allocate new points array, and assign most of the old stroke there */
1404                 gps->totpoints--;
1405                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1406                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
1407                 
1408                 /* free temp buffer */
1409                 MEM_freeN(pt_tmp);
1410                 
1411                 /* nothing left in stroke, so stop */
1412                 return 1;
1413         }
1414
1415         /* if first segment, just remove segment from the stroke */
1416         else if (i == 0) {
1417                 /* allocate new points array, and assign most of the old stroke there */
1418                 gps->totpoints--;
1419                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1420                 memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
1421                 
1422                 /* free temp buffer */
1423                 MEM_freeN(pt_tmp);
1424                 
1425                 /* no break here, as there might still be stuff to remove in this stroke */
1426                 return 0;
1427         }
1428
1429         /* segment occurs in 'middle' of stroke, so split */
1430         else {
1431                 /* duplicate stroke, and assign 'later' data to that stroke */
1432                 gsn= MEM_dupallocN(gps);
1433                 gsn->prev= gsn->next= NULL;
1434                 BLI_insertlinkafter(&gpf->strokes, gps, gsn);
1435                 
1436                 gsn->totpoints= gps->totpoints - i;
1437                 gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
1438                 memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
1439                 
1440                 /* adjust existing stroke  */
1441                 gps->totpoints= i;
1442                 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1443                 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
1444                 
1445                 /* free temp buffer */
1446                 MEM_freeN(pt_tmp);
1447                 
1448                 /* nothing left in stroke, so stop */
1449                 return 1;
1450         }
1451 }
1452
1453 /* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
1454 static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1)
1455 {
1456         /* simple within-radius check for now */
1457         if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
1458                 return 1;
1459         
1460         /* not inside */
1461         return 0;
1462
1463
1464 /* eraser tool - evaluation per stroke */
1465 static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
1466 {
1467         bGPDspoint *pt1, *pt2;
1468         short x0=0, y0=0, x1=0, y1=0;
1469         short xyval[2];
1470         int i;
1471         
1472         if (gps->totpoints == 0) {
1473                 /* just free stroke */
1474                 if (gps->points) 
1475                         MEM_freeN(gps->points);
1476                 BLI_freelinkN(&gpf->strokes, gps);
1477         }
1478         else if (gps->totpoints == 1) {
1479                 /* get coordinates */
1480                 if (gps->flag & GP_STROKE_3DSPACE) {
1481                         project_short(&gps->points->x, xyval);
1482                         x0= xyval[0];
1483                         y0= xyval[1];
1484                 }
1485                 else if (gps->flag & GP_STROKE_2DSPACE) {                       
1486                         ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval);
1487                         x0= xyval[0];
1488                         y0= xyval[1];
1489                 }
1490                 else {
1491                         x0= (gps->points->x / 1000 * p->sa->winx);
1492                         y0= (gps->points->y / 1000 * p->sa->winy);
1493                 }
1494                 
1495                 /* do boundbox check first */
1496                 if (BLI_in_rcti(rect, x0, y0)) {
1497                         /* only check if point is inside */
1498                         if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) {
1499                                 /* free stroke */
1500                                 MEM_freeN(gps->points);
1501                                 BLI_freelinkN(&gpf->strokes, gps);
1502                         }
1503                 }
1504         }
1505         else {  
1506                 /* loop over the points in the stroke, checking for intersections 
1507                  *      - an intersection will require the stroke to be split
1508                  */
1509                 for (i=0; (i+1) < gps->totpoints; i++) {
1510                         /* get points to work with */
1511                         pt1= gps->points + i;
1512                         pt2= gps->points + i + 1;
1513                         
1514                         /* get coordinates */
1515                         if (gps->flag & GP_STROKE_3DSPACE) {
1516                                 project_short(&pt1->x, xyval);
1517                                 x0= xyval[0];
1518                                 y0= xyval[1];
1519                                 
1520                                 project_short(&pt2->x, xyval);
1521                                 x1= xyval[0];
1522                                 y1= xyval[1];
1523                         }
1524                         else if (gps->flag & GP_STROKE_2DSPACE) {
1525                                 ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval);
1526                                 x0= xyval[0];
1527                                 y0= xyval[1];
1528                                 
1529                                 ipoco_to_areaco_noclip(p->v2d, &pt2->x, xyval);
1530                                 x1= xyval[0];
1531                                 y1= xyval[1];
1532                         }
1533                         else {
1534                                 x0= (pt1->x / 1000 * p->sa->winx);
1535                                 y0= (pt1->y / 1000 * p->sa->winy);
1536                                 x1= (pt2->x / 1000 * p->sa->winx);
1537                                 y1= (pt2->y / 1000 * p->sa->winy);
1538                         }
1539                         
1540                         /* check that point segment of the boundbox of the eraser stroke */
1541                         if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
1542                                 /* check if point segment of stroke had anything to do with
1543                                  * eraser region  (either within stroke painted, or on its lines)
1544                                  *      - this assumes that linewidth is irrelevant
1545                                  */
1546                                 if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
1547                                         /* if function returns true, break this loop (as no more point to check) */
1548                                         if (gp_stroke_eraser_splitdel(gpf, gps, i))
1549                                                 break;
1550                                 }
1551                         }
1552                 }
1553         }
1554 }
1555
1556 /* -------- */
1557
1558 /* erase strokes which fall under the eraser strokes */
1559 static void gp_stroke_doeraser (tGPsdata *p)
1560 {
1561         bGPDframe *gpf= p->gpf;
1562         bGPDstroke *gps, *gpn;
1563         rcti rect;
1564         
1565         /* rect is rectangle of eraser */
1566         rect.xmin= p->mval[0] - p->radius;
1567         rect.ymin= p->mval[1] - p->radius;
1568         rect.xmax= p->mval[0] + p->radius;
1569         rect.ymax= p->mval[1] + p->radius;
1570         
1571         /* loop over strokes, checking segments for intersections */
1572         for (gps= gpf->strokes.first; gps; gps= gpn) {
1573                 gpn= gps->next;
1574                 gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
1575         }
1576 }
1577
1578 /* ---------- 'Paint' Tool ------------ */
1579
1580 /* init new stroke */
1581 static void gp_paint_initstroke (tGPsdata *p, short paintmode)
1582 {       
1583         /* get active layer (or add a new one if non-existent) */
1584         p->gpl= gpencil_layer_getactive(p->gpd);
1585         if (p->gpl == NULL)
1586                 p->gpl= gpencil_layer_addnew(p->gpd);
1587         if (p->gpl->flag & GP_LAYER_LOCKED) {
1588                 p->status= GP_STATUS_ERROR;
1589                 if (G.f & G_DEBUG)
1590                         printf("Error: Cannot paint on locked layer \n");
1591                 return;
1592         }
1593                 
1594         /* get active frame (add a new one if not matching frame) */
1595         p->gpf= gpencil_layer_getframe(p->gpl, CFRA, 1);
1596         if (p->gpf == NULL) {
1597                 p->status= GP_STATUS_ERROR;
1598                 if (G.f & G_DEBUG) 
1599                         printf("Error: No frame created (gpencil_paint_init) \n");
1600                 return;
1601         }
1602         else
1603                 p->gpf->flag |= GP_FRAME_PAINT;
1604         
1605         /* set 'eraser' for this stroke if using eraser */
1606         p->paintmode= paintmode;
1607         if (p->paintmode == GP_PAINTMODE_ERASER)
1608                 p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
1609         
1610         /* check if points will need to be made in view-aligned space */
1611         if (p->gpd->flag & GP_DATA_VIEWALIGN) {
1612                 switch (p->sa->spacetype) {
1613                         case SPACE_VIEW3D:
1614                         {
1615                                 float *fp= give_cursor();
1616                                 initgrabz(fp[0], fp[1], fp[2]);
1617                                 
1618                                 p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
1619                         }
1620                                 break;
1621                         case SPACE_NODE:
1622                         {
1623                                 p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1624                         }
1625                                 break;
1626                         case SPACE_SEQ:
1627                         {
1628                                 /* for now, this is not applicable here... */
1629                                 //p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1630                         }
1631                                 break;
1632                         case SPACE_IMAGE:
1633                         {
1634                                 /* check if any ibuf available */
1635                                 if (p->ibuf)
1636                                         p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1637                         }
1638                                 break;
1639                 }
1640         }
1641 }
1642
1643 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1644 static void gp_paint_strokeend (tGPsdata *p)
1645 {
1646         /* check if doing eraser or not */
1647         if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
1648                 /* transfer stroke to frame */
1649                 gp_stroke_newfrombuffer(p);
1650         }
1651         
1652         /* clean up buffer now */
1653         gp_session_validatebuffer(p);
1654 }
1655
1656 /* finish off stroke painting operation */
1657 static void gp_paint_cleanup (tGPsdata *p)
1658 {
1659         /* finish off a stroke */
1660         gp_paint_strokeend(p);
1661         
1662         /* "unlock" frame */
1663         p->gpf->flag &= ~GP_FRAME_PAINT;
1664         
1665         /* add undo-push so stroke can be undone */
1666         /* FIXME: currently disabled, as it's impossible to get this working nice
1667          * as gpenci data is on currently screen-level (which isn't saved to undo files)
1668          */
1669         //BIF_undo_push("GPencil Stroke");
1670         
1671         /* force redraw after drawing action */
1672         force_draw_plus(SPACE_ACTION, 0);
1673 }
1674
1675 /* -------- */
1676
1677 /* main call to paint a new stroke */
1678 short gpencil_paint (short mousebutton, short paintmode)
1679 {
1680         tGPsdata p;
1681         float opressure, pressure;
1682         short ok = GP_STROKEADD_NORMAL;
1683         
1684         /* init paint-data */
1685         gp_session_initpaint(&p);
1686         if (p.status == GP_STATUS_ERROR) {
1687                 gp_session_cleanup(&p);
1688                 return 0;
1689         }
1690         gp_paint_initstroke(&p, paintmode);
1691         if (p.status == GP_STATUS_ERROR) {
1692                 gp_session_cleanup(&p);
1693                 return 0;
1694         }
1695         
1696         /* set cursor to indicate drawing */
1697         setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
1698         
1699         /* init drawing-device settings */
1700         getmouseco_areawin(p.mval);
1701         pressure = get_pressure();
1702         
1703         p.mvalo[0]= p.mval[0];
1704         p.mvalo[1]= p.mval[1];
1705         opressure= pressure;
1706         
1707         /* radius for eraser circle is thickness^2 */
1708         p.radius= p.gpl->thickness * p.gpl->thickness;
1709         
1710         /* start drawing eraser-circle (if applicable) */
1711         if (paintmode == GP_PAINTMODE_ERASER)
1712                 draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again
1713         
1714         /* only allow painting of single 'dots' if: 
1715          *      - pressure is not excessive (as it can be on some windows tablets)
1716          *      - draw-mode for active datablock is turned on
1717          *      - not erasing
1718          */
1719         if (paintmode != GP_PAINTMODE_ERASER) {
1720                 if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { 
1721                         gp_stroke_addpoint(&p, p.mval, pressure);
1722                 }
1723         }
1724         
1725         /* paint loop */
1726         do {
1727                 /* get current user input */
1728                 getmouseco_areawin(p.mval);
1729                 pressure = get_pressure();
1730                 
1731                 /* only add current point to buffer if mouse moved (otherwise wait until it does) */
1732                 if (paintmode == GP_PAINTMODE_ERASER) {
1733                         /* do 'live' erasing now */
1734                         gp_stroke_doeraser(&p);
1735                         
1736                         draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0);
1737                         force_draw(0);
1738                         
1739                         p.mvalo[0]= p.mval[0];
1740                         p.mvalo[1]= p.mval[1];
1741                 }
1742                 else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) {
1743                         /* try to add point */
1744                         ok= gp_stroke_addpoint(&p, p.mval, pressure);
1745                         
1746                         /* handle errors while adding point */
1747                         if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
1748                                 /* finish off old stroke */
1749                                 gp_paint_strokeend(&p);
1750                                 
1751                                 /* start a new stroke, starting from previous point */
1752                                 gp_stroke_addpoint(&p, p.mvalo, opressure);
1753                                 ok= gp_stroke_addpoint(&p, p.mval, pressure);
1754                         }
1755                         else if (ok == GP_STROKEADD_INVALID) {
1756                                 /* the painting operation cannot continue... */
1757                                 error("Cannot paint stroke");
1758                                 p.status = GP_STATUS_ERROR;
1759                                 
1760                                 if (G.f & G_DEBUG) 
1761                                         printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
1762                                 break;
1763                         }
1764                         force_draw(0);
1765                         
1766                         p.mvalo[0]= p.mval[0];
1767                         p.mvalo[1]= p.mval[1];
1768                         opressure= pressure;
1769                 }
1770                 else
1771                         BIF_wait_for_statechange();
1772                 
1773                 /* do mouse checking at the end, so don't check twice, and potentially
1774                  * miss a short tap 
1775                  */
1776         } while (get_mbut() & mousebutton);
1777         
1778         /* clear edit flags */
1779         G.f &= ~G_GREASEPENCIL;
1780         
1781         /* restore cursor to indicate end of drawing */
1782         setcursor_space(p.sa->spacetype, CURSOR_STD);
1783         
1784         /* check size of buffer before cleanup, to determine if anything happened here */
1785         if (paintmode == GP_PAINTMODE_ERASER) {
1786                 ok= 1; // fixme
1787                 draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0);
1788         }
1789         else
1790                 ok= p.gpd->sbuffer_size;
1791         
1792         /* cleanup */
1793         gp_paint_cleanup(&p);
1794         gp_session_cleanup(&p);
1795         
1796         /* done! return if a stroke was successfully added */
1797         return ok;
1798 }
1799
1800
1801 /* All event (loops) handling checking if stroke drawing should be initiated
1802  * should call this function.
1803  */
1804 short gpencil_do_paint (ScrArea *sa, short mbut)
1805 {
1806         bGPdata *gpd = gpencil_data_getactive(sa);
1807         short retval= 0;
1808         
1809         /* check if possible to do painting */
1810         if (gpd == NULL) 
1811                 return 0;
1812         
1813         /* currently, we will only 'paint' if:
1814          *      1. draw-mode on gpd is set (for accessibility reasons)
1815          *              a) single dots are only available by this method if a single click is made
1816          *              b) a straight line is drawn if ctrl-modifier is held (check is done when stroke is converted!)
1817          *      2. if shift-modifier is held + lmb -> 'quick paint'
1818          *
1819          *      OR
1820          * 
1821          * draw eraser stroke if:
1822          *      1. using the eraser on a tablet
1823          *      2. draw-mode on gpd is set (for accessiblity reasons)
1824          *              (eraser is mapped to right-mouse)
1825          *      3. Alt + 'select' mouse-button
1826          *              i.e.  if LMB = select: Alt-LMB
1827          *                        if RMB = select: Alt-RMB
1828          */
1829         if (get_activedevice() == 2) {
1830                 /* eraser on a tablet - always try to erase strokes */
1831                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1832         }
1833         else if (gpd->flag & GP_DATA_EDITPAINT) {
1834                 /* try to paint/erase */
1835                 if (mbut == L_MOUSE)
1836                         retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
1837                 else if (mbut == R_MOUSE)
1838                         retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1839         }
1840         else if (!(gpd->flag & GP_DATA_LMBPLOCK)) {
1841                 /* try to paint/erase as not locked */
1842                 if ((G.qual == LR_SHIFTKEY) && (mbut == L_MOUSE)) {
1843                         retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
1844                 }
1845                 else if (G.qual == LR_ALTKEY) {
1846                         if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE))
1847                                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1848                         else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE))
1849                                 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
1850                 }
1851         }
1852         
1853         /* return result of trying to paint */
1854         return retval;
1855 }
1856
1857 /* ************************************************** */