4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2008, Blender Foundation
21 * This is a new part of Blender
23 * Contributor(s): Joshua Leung
25 * ***** END GPL LICENSE BLOCK *****
38 #include "MEM_guardedalloc.h"
42 #include "IMB_imbuf.h"
43 #include "IMB_imbuf_types.h"
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
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"
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 #include "BKE_library.h"
69 #include "BIF_glutil.h"
70 #include "BIF_butspace.h"
71 #include "BIF_drawseq.h"
72 #include "BIF_editarmature.h"
73 #include "BIF_editview.h"
74 #include "BIF_graphics.h"
75 #include "BIF_interface.h"
76 #include "BIF_mywindow.h"
77 #include "BIF_resources.h"
78 #include "BIF_space.h"
79 #include "BIF_screen.h"
80 #include "BIF_toolbox.h"
81 #include "BIF_toets.h"
83 #include "BDR_gpencil.h"
84 #include "BIF_drawgpencil.h"
86 #include "BDR_editobject.h"
88 #include "BSE_drawipo.h"
89 #include "BSE_headerbuttons.h"
94 #include "PIL_time.h" /* sleep */
97 /* ************************************************** */
100 /* --------- Memory Management ------------ */
102 /* Free strokes belonging to a gp-frame */
103 void free_gpencil_strokes (bGPDframe *gpf)
105 bGPDstroke *gps, *gpsn;
108 if (gpf == NULL) return;
111 for (gps= gpf->strokes.first; gps; gps= gpsn) {
114 /* free stroke memory arrays, then stroke itself */
115 if (gps->points) MEM_freeN(gps->points);
116 BLI_freelinkN(&gpf->strokes, gps);
120 /* Free all of a gp-layer's frames */
121 void free_gpencil_frames (bGPDlayer *gpl)
123 bGPDframe *gpf, *gpfn;
126 if (gpl == NULL) return;
129 for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
132 /* free strokes and their associated memory */
133 free_gpencil_strokes(gpf);
134 BLI_freelinkN(&gpl->frames, gpf);
138 /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
139 void free_gpencil_layers (ListBase *list)
141 bGPDlayer *gpl, *gpln;
144 if (list == NULL) return;
147 for (gpl= list->first; gpl; gpl= gpln) {
150 /* free layers and their data */
151 free_gpencil_frames(gpl);
152 BLI_freelinkN(list, gpl);
156 /* Free gp-data and all it's related data */
157 void free_gpencil_data (bGPdata *gpd)
159 /* free layers then data itself */
160 free_gpencil_layers(&gpd->layers);
164 /* -------- Container Creation ---------- */
166 /* add a new gp-frame to the given layer */
167 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
173 if ((gpl == NULL) || (cframe <= 0))
176 /* allocate memory for this frame */
177 gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
178 gpf->framenum= cframe;
180 /* find appropriate place to add frame */
181 if (gpl->frames.first) {
182 for (gf= gpl->frames.first; gf; gf= gf->next) {
183 /* check if frame matches one that is supposed to be added */
184 if (gf->framenum == cframe) {
189 /* if current frame has already exceeded the frame to add, add before */
190 if (gf->framenum > cframe) {
191 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
198 /* check whether frame was added successfully */
201 printf("Error: frame (%d) existed already for this layer \n", cframe);
203 else if (state == 0) {
204 /* add to end then! */
205 BLI_addtail(&gpl->frames, gpf);
212 /* add a new gp-layer and make it the active layer */
213 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
217 /* check that list is ok */
221 /* allocate memory for frame and add to end of list */
222 gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
224 /* add to datablock */
225 BLI_addtail(&gpd->layers, gpl);
227 /* set basic settings */
232 sprintf(gpl->info, "GP_Layer");
233 BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
235 /* make this one the active one */
236 gpencil_layer_setactive(gpd, gpl);
242 /* add a new gp-datablock */
243 bGPdata *gpencil_data_addnew (void)
247 /* allocate memory for a new block */
248 gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
250 /* initial settings */
251 gpd->flag = (GP_DATA_DISPINFO|GP_DATA_EXPAND);
256 /* -------- Data Duplication ---------- */
258 /* make a copy of a given gpencil frame */
259 bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
261 bGPDstroke *gps, *gpsd;
268 /* make a copy of the source frame */
269 dst= MEM_dupallocN(src);
270 dst->prev= dst->next= NULL;
273 dst->strokes.first = dst->strokes.last= NULL;
274 for (gps= src->strokes.first; gps; gps= gps->next) {
275 /* make copy of source stroke, then adjust pointer to points too */
276 gpsd= MEM_dupallocN(gps);
277 gpsd->points= MEM_dupallocN(gps->points);
279 BLI_addtail(&dst->strokes, gpsd);
282 /* return new frame */
286 /* make a copy of a given gpencil layer */
287 bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src)
289 bGPDframe *gpf, *gpfd;
296 /* make a copy of source layer */
297 dst= MEM_dupallocN(src);
298 dst->prev= dst->next= NULL;
301 dst->frames.first= dst->frames.last= NULL;
302 for (gpf= src->frames.first; gpf; gpf= gpf->next) {
303 /* make a copy of source frame */
304 gpfd= gpencil_frame_duplicate(gpf);
305 BLI_addtail(&dst->frames, gpfd);
307 /* if source frame was the current layer's 'active' frame, reassign that too */
308 if (gpf == dst->actframe)
312 /* return new layer */
316 /* make a copy of a given gpencil datablock */
317 bGPdata *gpencil_data_duplicate (bGPdata *src)
319 bGPDlayer *gpl, *gpld;
326 /* make a copy of the base-data */
327 dst= MEM_dupallocN(src);
330 dst->layers.first= dst->layers.last= NULL;
331 for (gpl= src->layers.first; gpl; gpl= gpl->next) {
332 /* make a copy of source layer and its data */
333 gpld= gpencil_layer_duplicate(gpl);
334 BLI_addtail(&dst->layers, gpld);
341 /* ----------- GP-Datablock API ------------- */
343 /* get the appropriate bGPdata from the active/given context */
344 bGPdata *gpencil_data_getactive (ScrArea *sa)
347 if ((sa == NULL) && (curarea == NULL))
352 /* handle depending on spacetype */
353 switch (sa->spacetype) {
356 View3D *v3d= sa->spacedata.first;
362 SpaceNode *snode= sa->spacedata.first;
368 SpaceSeq *sseq= sa->spacedata.first;
370 /* only applicable for image modes */
377 SpaceImage *sima= sa->spacedata.first;
387 /* set bGPdata for the active/given context, and return success/fail */
388 short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
391 if ((sa == NULL) && (curarea == NULL))
398 /* handle depending on spacetype */
399 // TODO: someday we should have multi-user data, so no need to loose old data
400 switch (sa->spacetype) {
403 View3D *v3d= sa->spacedata.first;
405 /* free the existing block */
407 free_gpencil_data(v3d->gpd);
415 SpaceNode *snode= sa->spacedata.first;
417 /* free the existing block */
419 free_gpencil_data(snode->gpd);
422 /* set special settings */
423 gpd->flag |= GP_DATA_VIEWALIGN;
430 SpaceSeq *sseq= sa->spacedata.first;
432 /* only applicable if right mode */
434 /* free the existing block */
436 free_gpencil_data(sseq->gpd);
445 SpaceImage *sima= sa->spacedata.first;
448 free_gpencil_data(sima->gpd);
460 /* return the ScrArea that has the given GP-datablock
461 * - assumes that only searching in current screen
462 * - is based on GP-datablocks only being able to
463 * exist for one area at a time (i.e. not multiuser)
465 ScrArea *gpencil_data_findowner (bGPdata *gpd)
473 /* loop over all scrareas for current screen, and check if that area has this gpd */
474 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
475 /* use get-active func to see if match */
476 if (gpencil_data_getactive(sa) == gpd)
484 /* -------- GP-Frame API ---------- */
486 /* delete the last stroke of the given frame */
487 void gpencil_frame_delete_laststroke (bGPDframe *gpf)
489 bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
492 if (ELEM(NULL, gpf, gps))
495 /* free the stroke and its data */
496 MEM_freeN(gps->points);
497 BLI_freelinkN(&gpf->strokes, gps);
500 /* -------- GP-Layer API ---------- */
502 /* get the appropriate gp-frame from a given layer
503 * - this sets the layer's actframe var (if allowed to)
504 * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
506 bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
508 bGPDframe *gpf = NULL;
512 if (gpl == NULL) return NULL;
513 if (cframe <= 0) cframe = 1;
515 /* check if there is already an active frame */
519 /* do not allow any changes to layer's active frame if layer is locked */
520 if (gpl->flag & GP_LAYER_LOCKED)
522 /* do not allow any changes to actframe if frame has painting tag attached to it */
523 if (gpf->flag & GP_FRAME_PAINT)
526 /* try to find matching frame */
527 if (gpf->framenum < cframe) {
528 for (; gpf; gpf= gpf->next) {
529 if (gpf->framenum == cframe) {
533 else if ((gpf->next) && (gpf->next->framenum > cframe)) {
539 /* set the appropriate frame */
541 if ((found) && (gpf->framenum == cframe))
544 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
549 gpl->actframe= gpl->frames.last;
552 for (; gpf; gpf= gpf->prev) {
553 if (gpf->framenum <= cframe) {
559 /* set the appropriate frame */
561 if ((found) && (gpf->framenum == cframe))
564 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
569 gpl->actframe= gpl->frames.first;
572 else if (gpl->frames.first) {
573 /* check which of the ends to start checking from */
574 const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
575 const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
577 if (abs(cframe-first) > abs(cframe-last)) {
578 /* find gp-frame which is less than or equal to cframe */
579 for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
580 if (gpf->framenum <= cframe) {
587 /* find gp-frame which is less than or equal to cframe */
588 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
589 if (gpf->framenum <= cframe) {
596 /* set the appropriate frame */
598 if ((found) && (gpf->framenum == cframe))
601 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
606 /* unresolved errogenous situation! */
607 printf("Error: cannot find appropriate gp-frame \n");
608 /* gpl->actframe should still be NULL */
612 /* currently no frames (add if allowed to) */
614 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
616 /* don't do anything... this may be when no frames yet! */
617 /* gpl->actframe should still be NULL */
622 return gpl->actframe;
625 /* delete the given frame from a layer */
626 void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
629 if (ELEM(NULL, gpl, gpf))
632 /* free the frame and its data */
633 free_gpencil_strokes(gpf);
634 BLI_freelinkN(&gpl->frames, gpf);
635 gpl->actframe = NULL;
638 /* get the active gp-layer for editing */
639 bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
644 if (ELEM(NULL, gpd, gpd->layers.first))
647 /* loop over layers until found (assume only one active) */
648 for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
649 if (gpl->flag & GP_LAYER_ACTIVE)
653 /* no active layer found */
657 /* set the active gp-layer */
658 void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
663 if (ELEM3(NULL, gpd, gpd->layers.first, active))
666 /* loop over layers deactivating all */
667 for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
668 gpl->flag &= ~GP_LAYER_ACTIVE;
670 /* set as active one */
671 active->flag |= GP_LAYER_ACTIVE;
674 /* delete the active gp-layer */
675 void gpencil_layer_delactive (bGPdata *gpd)
677 bGPDlayer *gpl= gpencil_layer_getactive(gpd);
680 if (ELEM(NULL, gpd, gpl))
684 free_gpencil_frames(gpl);
685 BLI_freelinkN(&gpd->layers, gpl);
688 /* ************************************************** */
689 /* GREASE-PENCIL EDITING - Tools */
691 /* --------- Data Deletion ---------- */
693 /* delete the last stroke on the active layer */
694 void gpencil_delete_laststroke (bGPdata *gpd)
696 bGPDlayer *gpl= gpencil_layer_getactive(gpd);
697 bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
699 gpencil_frame_delete_laststroke(gpf);
702 /* delete the active frame */
703 void gpencil_delete_actframe (bGPdata *gpd)
705 bGPDlayer *gpl= gpencil_layer_getactive(gpd);
706 bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
708 gpencil_layer_delframe(gpl, gpf);
713 /* delete various grase-pencil elements
714 * mode: 1 - last stroke
718 void gpencil_delete_operation (short mode)
722 /* get datablock to work on */
723 gpd= gpencil_data_getactive(NULL);
724 if (gpd == NULL) return;
727 case 1: /* last stroke */
728 gpencil_delete_laststroke(gpd);
730 case 2: /* active frame */
731 gpencil_delete_actframe(gpd);
733 case 3: /* active layer */
734 gpencil_layer_delactive(gpd);
738 /* redraw and undo-push */
739 BIF_undo_push("GPencil Delete");
740 allqueue(REDRAWVIEW3D, 0);
743 /* display a menu for deleting different grease-pencil elements */
744 void gpencil_delete_menu (void)
746 bGPdata *gpd= gpencil_data_getactive(NULL);
749 /* only show menu if it will be relevant */
750 if (gpd == NULL) return;
752 mode= pupmenu("Grease Pencil Erase...%t|Last Stroke%x1|Active Frame%x2|Active Layer%x3");
753 if (mode <= 0) return;
755 gpencil_delete_operation(mode);
758 /* --------- Data Conversion ---------- */
760 /* convert the coordinates from the given stroke point into 3d-coordinates */
761 static void gp_strokepoint_convertcoords (bGPDstroke *gps, bGPDspoint *pt, float p3d[3])
763 if (gps->flag & GP_STROKE_3DSPACE) {
764 /* directly use 3d-coordinates */
765 VecCopyf(p3d, &pt->x);
768 short mval[2], mx, my;
769 float *fp= give_cursor();
772 /* get screen coordinate */
773 if (gps->flag & GP_STROKE_2DSPACE) {
774 View2D *v2d= spacelink_get_view2d(curarea->spacedata.first);
775 ipoco_to_areaco_noclip(v2d, &pt->x, mval);
778 mval[0]= (short)(pt->x / 1000 * curarea->winx);
779 mval[1]= (short)(pt->y / 1000 * curarea->winy);
784 /* convert screen coordinate to 3d coordinates
785 * - method taken from editview.c - mouse_cursor()
787 project_short_noclip(fp, mval);
788 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
789 VecSubf(p3d, fp, dvec);
795 /* convert stroke to 3d path */
796 static void gp_stroke_to_path (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
803 /* create new 'nurb' within the curve */
804 nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
806 nu->pntsu= gps->totpoints;
808 nu->orderu= gps->totpoints;
809 nu->flagu= 2; /* endpoint */
812 nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints");
815 for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
818 /* get coordinates to add at */
819 gp_strokepoint_convertcoords(gps, pt, p3d);
820 VecCopyf(bp->vec, p3d);
824 bp->radius = bp->weight = pt->pressure * gpl->thickness;
827 /* add nurb to curve */
828 BLI_addtail(&cu->nurb, nu);
831 /* convert stroke to 3d bezier */
832 static void gp_stroke_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
839 /* create new 'nurb' within the curve */
840 nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
842 nu->pntsu= gps->totpoints;
846 nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts");
849 for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) {
852 /* get coordinates to add at */
853 gp_strokepoint_convertcoords(gps, pt, p3d);
855 /* TODO: maybe in future the handles shouldn't be in same place */
856 VecCopyf(bezt->vec[0], p3d);
857 VecCopyf(bezt->vec[1], p3d);
858 VecCopyf(bezt->vec[2], p3d);
861 bezt->h1= bezt->h2= HD_FREE;
862 bezt->f1= bezt->f2= bezt->f3= SELECT;
863 bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f;
866 /* must calculate handles or else we crash */
869 /* add nurb to curve */
870 BLI_addtail(&cu->nurb, nu);
873 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
874 static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl, short mode)
876 bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
882 if (ELEM3(NULL, gpd, gpl, gpf))
885 /* only convert if there are any strokes on this layer's frame to convert */
886 if (gpf->strokes.first == NULL)
889 /* init the curve object (remove rotation and get curve data from it)
890 * - must clear transforms set on object, as those skew our results
892 add_object_draw(OB_CURVE);
894 ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
895 ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
899 /* rename object and curve to layer name */
900 rename_id((ID *)ob, gpl->info);
901 rename_id((ID *)cu, gpl->info);
903 /* add points to curve */
904 for (gps= gpf->strokes.first; gps; gps= gps->next) {
907 gp_stroke_to_path(gpl, gps, cu);
910 gp_stroke_to_bezier(gpl, gps, cu);
918 /* convert a stroke to a bone chain */
919 static void gp_stroke_to_bonechain (bGPDlayer *gpl, bGPDstroke *gps, bArmature *arm, ListBase *bones)
921 EditBone *ebo, *prev=NULL;
922 bGPDspoint *pt, *ptn;
925 /* add each segment separately */
926 for (i=0, pt=gps->points, ptn=gps->points+1; i < (gps->totpoints-1); prev=ebo, i++, pt++, ptn++) {
927 float p3da[3], p3db[3];
929 /* get coordinates to add at */
930 gp_strokepoint_convertcoords(gps, pt, p3da);
931 gp_strokepoint_convertcoords(gps, ptn, p3db);
933 /* allocate new bone */
934 ebo= MEM_callocN(sizeof(EditBone), "eBone");
936 VecCopyf(ebo->head, p3da);
937 VecCopyf(ebo->tail, p3db);
939 /* add new bone - note: sync with editarmature.c::add_editbone() */
941 BLI_strncpy(ebo->name, "Stroke", 32);
942 unique_editbone_name(bones, ebo->name, NULL);
944 BLI_addtail(bones, ebo);
948 ebo->flag |= BONE_CONNECTED;
956 ebo->rad_head= pt->pressure * gpl->thickness * 0.1f;
957 ebo->rad_tail= ptn->pressure * gpl->thickness * 0.1f;
959 ebo->layer= arm->layer;
967 /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
968 static void gp_layer_to_armature (bGPdata *gpd, bGPDlayer *gpl, short mode)
970 bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
974 ListBase bones = {0,0};
977 if (ELEM3(NULL, gpd, gpl, gpf))
980 /* only convert if there are any strokes on this layer's frame to convert */
981 if (gpf->strokes.first == NULL)
984 /* init the armature object (remove rotation and assign armature data to it)
985 * - must clear transforms set on object, as those skew our results
987 add_object_draw(OB_ARMATURE);
989 ob->loc[0]= ob->loc[1]= ob->loc[2]= 0;
990 ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
993 /* rename object and armature to layer name */
994 rename_id((ID *)ob, gpl->info);
995 rename_id((ID *)arm, gpl->info);
997 /* convert segments to bones, strokes to bone chains */
998 for (gps= gpf->strokes.first; gps; gps= gps->next) {
999 gp_stroke_to_bonechain(gpl, gps, arm, &bones);
1002 /* adjust roll of bones
1003 * - set object as EditMode object, but need to clear afterwards!
1004 * - use 'align to world z-up' option
1007 /* set our data as if we're in editmode to fool auto_align_armature() */
1009 G.edbo.first = bones.first;
1010 G.edbo.last = bones.last;
1012 /* WARNING: need to make sure this magic number doesn't change */
1013 auto_align_armature(2);
1015 /* clear editbones (not needed anymore) */
1016 G.edbo.first= G.edbo.last= NULL;
1020 /* flush editbones to armature */
1021 editbones_to_armature(&bones, ob);
1022 if (bones.first) BLI_freelistN(&bones);
1027 /* convert grease-pencil strokes to another representation
1028 * mode: 1 - Active layer to path
1029 * 2 - Active layer to bezier
1030 * 3 - Active layer to armature
1032 void gpencil_convert_operation (short mode)
1035 float *fp= give_cursor();
1037 /* get datablock to work on */
1038 gpd= gpencil_data_getactive(NULL);
1039 if (gpd == NULL) return;
1041 /* initialise 3d-cursor correction globals */
1042 initgrabz(fp[0], fp[1], fp[2]);
1044 /* handle selection modes */
1046 case 1: /* active layer only (to path) */
1047 case 2: /* active layer only (to bezier) */
1049 bGPDlayer *gpl= gpencil_layer_getactive(gpd);
1050 gp_layer_to_curve(gpd, gpl, mode);
1053 case 3: /* active layer only (to armature) */
1055 bGPDlayer *gpl= gpencil_layer_getactive(gpd);
1056 gp_layer_to_armature(gpd, gpl, mode);
1061 /* redraw and undo-push */
1062 BIF_undo_push("GPencil Convert");
1063 allqueue(REDRAWVIEW3D, 0);
1064 allqueue(REDRAWOOPS, 0);
1067 /* display a menu for converting grease-pencil strokes */
1068 void gpencil_convert_menu (void)
1070 bGPdata *gpd= gpencil_data_getactive(NULL);
1073 /* only show menu if it will be relevant */
1074 if (gpd == NULL) return;
1076 mode= pupmenu("Grease Pencil Convert %t|Active Layer To Path%x1|Active Layer to Bezier%x2|Active Layer to Armature%x3");
1077 if (mode <= 0) return;
1079 gpencil_convert_operation(mode);
1082 /* ************************************************** */
1083 /* GREASE-PENCIL EDITING MODE - Painting */
1085 /* ---------- 'Globals' and Defines ----------------- */
1087 /* maximum sizes of gp-session buffer */
1088 #define GP_STROKE_BUFFER_MAX 5000
1090 /* Macros for accessing sensitivity thresholds... */
1091 /* minimum number of pixels mouse should move before new point created */
1092 #define MIN_MANHATTEN_PX (U.gp_manhattendist)
1093 /* minimum length of new segment before new point can be added */
1094 #define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
1096 /* macro to test if only converting endpoints - only for use when converting! */
1097 #define GP_BUFFER2STROKE_ENDPOINTS ((gpd->flag & GP_DATA_EDITPAINT) && (G.qual & LR_CTRLKEY))
1101 /* Temporary 'Stroke' Operation data */
1102 typedef struct tGPsdata {
1103 ScrArea *sa; /* area where painting originated */
1104 View2D *v2d; /* needed for GP_STROKE_2DSPACE */
1106 ImBuf *ibuf; /* needed for GP_STROKE_2DIMAGE */
1107 struct IBufViewSettings {
1108 int offsx, offsy; /* offsets */
1109 int sizex, sizey; /* dimensions to use as scale-factor */
1110 } im2d_settings; /* needed for GP_STROKE_2DIMAGE */
1112 bGPdata *gpd; /* gp-datablock layer comes from */
1113 bGPDlayer *gpl; /* layer we're working on */
1114 bGPDframe *gpf; /* frame we're working on */
1116 short status; /* current status of painting */
1117 short paintmode; /* mode for painting */
1119 short mval[2]; /* current mouse-position */
1120 short mvalo[2]; /* previous recorded mouse-position */
1122 float pressure; /* current stylus pressure */
1123 float opressure; /* previous stylus pressure */
1125 short radius; /* radius of influence for eraser */
1128 /* values for tGPsdata->status */
1130 GP_STATUS_NORMAL = 0, /* running normally */
1131 GP_STATUS_ERROR, /* something wasn't correctly set up */
1132 GP_STATUS_DONE /* painting done */
1135 /* values for tGPsdata->paintmode */
1137 GP_PAINTMODE_DRAW = 0,
1141 /* Return flags for adding points to stroke buffer */
1143 GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
1144 GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
1145 GP_STROKEADD_NORMAL, /* point was successfully added */
1146 GP_STROKEADD_FULL /* cannot add any more points to buffer */
1149 /* ---------- Stroke Editing ------------ */
1151 /* clear the session buffers (call this before AND after a paint operation) */
1152 static void gp_session_validatebuffer (tGPsdata *p)
1154 bGPdata *gpd= p->gpd;
1156 /* clear memory of buffer (or allocate it if starting a new session) */
1158 memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
1160 gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
1163 gpd->sbuffer_size = 0;
1166 gpd->sbuffer_sflag= 0;
1169 /* check if the current mouse position is suitable for adding a new point */
1170 static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2])
1172 short dx= abs(mval[0] - pmval[0]);
1173 short dy= abs(mval[1] - pmval[1]);
1175 /* check if mouse moved at least certain distance on both axes (best case) */
1176 if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
1179 /* check if the distance since the last point is significant enough */
1180 // future optimisation: sqrt here may be too slow?
1181 else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX)
1184 /* mouse 'didn't move' */
1189 /* convert screen-coordinates to buffer-coordinates */
1190 static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
1192 bGPdata *gpd= p->gpd;
1194 /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
1195 if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
1196 const short mx=mval[0], my=mval[1];
1197 float *fp= give_cursor();
1200 /* Current method just converts each point in screen-coordinates to
1201 * 3D-coordinates using the 3D-cursor as reference. In general, this
1202 * works OK, but it could of course be improved.
1205 * - investigate using nearest point(s) on a previous stroke as
1206 * reference point instead or as offset, for easier stroke matching
1207 * - investigate projection onto geometry (ala retopo)
1210 /* method taken from editview.c - mouse_cursor() */
1211 project_short_noclip(fp, mval);
1212 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
1213 VecSubf(out, fp, dvec);
1216 /* 2d - on 'canvas' (assume that p->v2d is set) */
1217 else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
1220 areamouseco_to_ipoco(p->v2d, mval, &x, &y);
1226 /* 2d - on image 'canvas' (assume that p->v2d is set) */
1227 else if (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) {
1228 int sizex, sizey, offsx, offsy;
1230 /* get stored settings
1231 * - assume that these have been set already (there are checks that set sane 'defaults' just in case)
1233 sizex= p->im2d_settings.sizex;
1234 sizey= p->im2d_settings.sizey;
1235 offsx= p->im2d_settings.offsx;
1236 offsy= p->im2d_settings.offsy;
1238 /* calculate new points */
1239 out[0]= (float)(mval[0] - offsx) / (float)sizex;
1240 out[1]= (float)(mval[1] - offsy) / (float)sizey;
1243 /* 2d - relative to screen (viewport area) */
1245 out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
1246 out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
1250 /* add current stroke-point to buffer (returns whether point was successfully added) */
1251 static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
1253 bGPdata *gpd= p->gpd;
1256 /* check if still room in buffer */
1257 if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
1258 return GP_STROKEADD_OVERFLOW;
1260 /* get pointer to destination point */
1261 pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
1263 /* store settings */
1266 pt->pressure= pressure;
1268 /* increment counters */
1269 gpd->sbuffer_size++;
1271 /* check if another operation can still occur */
1272 if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
1273 return GP_STROKEADD_FULL;
1275 return GP_STROKEADD_NORMAL;
1278 /* smooth a stroke (in buffer) before storing it */
1279 static void gp_stroke_smooth (tGPsdata *p)
1281 bGPdata *gpd= p->gpd;
1282 int i=0, cmx=gpd->sbuffer_size;
1284 /* only smooth if smoothing is enabled, and we're not doing a straight line */
1285 if (!(U.gp_settings & GP_PAINT_DOSMOOTH) || GP_BUFFER2STROKE_ENDPOINTS)
1288 /* don't try if less than 2 points in buffer */
1289 if ((cmx <= 2) || (gpd->sbuffer == NULL))
1292 /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
1293 for (i=0; i < gpd->sbuffer_size; i++) {
1294 tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
1295 tGPspoint *pb= (i-1 > 0)?(pc-1):(pc);
1296 tGPspoint *pa= (i-2 > 0)?(pc-2):(pb);
1297 tGPspoint *pd= (i+1 < cmx)?(pc+1):(pc);
1298 tGPspoint *pe= (i+2 < cmx)?(pc+2):(pd);
1300 pc->x= (short)(0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
1301 pc->y= (short)(0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
1305 /* simplify a stroke (in buffer) before storing it
1306 * - applies a reverse Chaikin filter
1307 * - code adapted from etch-a-ton branch (editarmature_sketch.c)
1309 static void gp_stroke_simplify (tGPsdata *p)
1311 bGPdata *gpd= p->gpd;
1312 tGPspoint *old_points= (tGPspoint *)gpd->sbuffer;
1313 short num_points= gpd->sbuffer_size;
1314 short flag= gpd->sbuffer_sflag;
1317 /* only simplify if simlification is enabled, and we're not doing a straight line */
1318 if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || GP_BUFFER2STROKE_ENDPOINTS)
1321 /* don't simplify if less than 4 points in buffer */
1322 if ((num_points <= 2) || (old_points == NULL))
1325 /* clear buffer (but don't free mem yet) so that we can write to it
1326 * - firstly set sbuffer to NULL, so a new one is allocated
1327 * - secondly, reset flag after, as it gets cleared auto
1330 gp_session_validatebuffer(p);
1331 gpd->sbuffer_sflag = flag;
1333 /* macro used in loop to get position of new point
1334 * - used due to the mixture of datatypes in use here
1336 #define GP_SIMPLIFY_AVPOINT(offs, sfac) \
1338 co[0] += (float)(old_points[offs].x * sfac); \
1339 co[1] += (float)(old_points[offs].y * sfac); \
1340 pressure += old_points[offs].pressure * sfac; \
1343 for (i = 0, j = 0; i < num_points; i++)
1347 float co[2], pressure;
1350 /* initialise values */
1355 /* using macro, calculate new point */
1356 GP_SIMPLIFY_AVPOINT(j, -0.25f);
1357 GP_SIMPLIFY_AVPOINT(j+1, 0.75f);
1358 GP_SIMPLIFY_AVPOINT(j+2, 0.75f);
1359 GP_SIMPLIFY_AVPOINT(j+3, -0.25f);
1361 /* set values for adding */
1362 mco[0]= (short)co[0];
1363 mco[1]= (short)co[1];
1365 /* ignore return values on this... assume to be ok for now */
1366 gp_stroke_addpoint(p, mco, pressure);
1372 /* free old buffer */
1373 MEM_freeN(old_points);
1377 /* make a new stroke from the buffer data */
1378 static void gp_stroke_newfrombuffer (tGPsdata *p)
1380 bGPdata *gpd= p->gpd;
1386 /* get total number of points to allocate space for:
1387 * - in 'Draw Mode', holding the Ctrl-Modifier will only take endpoints
1388 * - otherwise, do whole stroke
1390 if (GP_BUFFER2STROKE_ENDPOINTS)
1391 totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size;
1393 totelem = gpd->sbuffer_size;
1395 /* exit with error if no valid points from this stroke */
1398 printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
1402 /* allocate memory for a new stroke */
1403 gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
1405 /* allocate enough memory for a continuous array for storage points */
1406 pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
1408 /* copy appropriate settings for stroke */
1409 gps->totpoints= totelem;
1410 gps->thickness= p->gpl->thickness;
1411 gps->flag= gpd->sbuffer_sflag;
1413 /* copy points from the buffer to the stroke */
1414 if (GP_BUFFER2STROKE_ENDPOINTS) {
1415 /* 'Draw Mode' + Ctrl-Modifier - only endpoints */
1420 /* convert screen-coordinates to appropriate coordinates (and store them) */
1421 gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1424 pt->pressure= ptc->pressure;
1430 /* last point if applicable */
1431 ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
1433 /* convert screen-coordinates to appropriate coordinates (and store them) */
1434 gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1437 pt->pressure= ptc->pressure;
1441 /* convert all points (normal behaviour) */
1442 for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
1443 /* convert screen-coordinates to appropriate coordinates (and store them) */
1444 gp_stroke_convertcoords(p, &ptc->x, &pt->x);
1447 pt->pressure= ptc->pressure;
1453 /* add stroke to frame */
1454 BLI_addtail(&p->gpf->strokes, gps);
1457 /* --- 'Eraser' for 'Paint' Tool ------ */
1459 /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
1460 static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
1462 bGPDspoint *pt_tmp= gps->points;
1463 bGPDstroke *gsn = NULL;
1465 /* if stroke only had two points, get rid of stroke */
1466 if (gps->totpoints == 2) {
1467 /* free stroke points, then stroke */
1469 BLI_freelinkN(&gpf->strokes, gps);
1471 /* nothing left in stroke, so stop */
1475 /* if last segment, just remove segment from the stroke */
1476 else if (i == gps->totpoints - 2) {
1477 /* allocate new points array, and assign most of the old stroke there */
1479 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1480 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
1482 /* free temp buffer */
1485 /* nothing left in stroke, so stop */
1489 /* if first segment, just remove segment from the stroke */
1491 /* allocate new points array, and assign most of the old stroke there */
1493 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1494 memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
1496 /* free temp buffer */
1499 /* no break here, as there might still be stuff to remove in this stroke */
1503 /* segment occurs in 'middle' of stroke, so split */
1505 /* duplicate stroke, and assign 'later' data to that stroke */
1506 gsn= MEM_dupallocN(gps);
1507 gsn->prev= gsn->next= NULL;
1508 BLI_insertlinkafter(&gpf->strokes, gps, gsn);
1510 gsn->totpoints= gps->totpoints - i;
1511 gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
1512 memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
1514 /* adjust existing stroke */
1516 gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
1517 memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
1519 /* free temp buffer */
1522 /* nothing left in stroke, so stop */
1527 /* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
1528 static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1)
1530 /* simple within-radius check for now */
1531 if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
1538 /* eraser tool - evaluation per stroke */
1539 static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
1541 bGPDspoint *pt1, *pt2;
1542 short x0=0, y0=0, x1=0, y1=0;
1546 if (gps->totpoints == 0) {
1547 /* just free stroke */
1549 MEM_freeN(gps->points);
1550 BLI_freelinkN(&gpf->strokes, gps);
1552 else if (gps->totpoints == 1) {
1553 /* get coordinates */
1554 if (gps->flag & GP_STROKE_3DSPACE) {
1555 project_short(&gps->points->x, xyval);
1559 else if (gps->flag & GP_STROKE_2DSPACE) {
1560 ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval);
1564 else if (gps->flag & GP_STROKE_2DIMAGE) {
1565 int offsx, offsy, sizex, sizey;
1567 /* get stored settings */
1568 sizex= p->im2d_settings.sizex;
1569 sizey= p->im2d_settings.sizey;
1570 offsx= p->im2d_settings.offsx;
1571 offsy= p->im2d_settings.offsy;
1573 /* calculate new points */
1574 x0= (short)((gps->points->x * sizex) + offsx);
1575 y0= (short)((gps->points->y * sizey) + offsy);
1578 x0= (short)(gps->points->x / 1000 * p->sa->winx);
1579 y0= (short)(gps->points->y / 1000 * p->sa->winy);
1582 /* do boundbox check first */
1583 if (BLI_in_rcti(rect, x0, y0)) {
1584 /* only check if point is inside */
1585 if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) {
1587 MEM_freeN(gps->points);
1588 BLI_freelinkN(&gpf->strokes, gps);
1593 /* loop over the points in the stroke, checking for intersections
1594 * - an intersection will require the stroke to be split
1596 for (i=0; (i+1) < gps->totpoints; i++) {
1597 /* get points to work with */
1598 pt1= gps->points + i;
1599 pt2= gps->points + i + 1;
1601 /* get coordinates */
1602 if (gps->flag & GP_STROKE_3DSPACE) {
1603 project_short(&pt1->x, xyval);
1607 project_short(&pt2->x, xyval);
1611 else if (gps->flag & GP_STROKE_2DSPACE) {
1612 ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval);
1616 ipoco_to_areaco_noclip(p->v2d, &pt2->x, xyval);
1620 else if (gps->flag & GP_STROKE_2DIMAGE) {
1621 int offsx, offsy, sizex, sizey;
1623 /* get stored settings */
1624 sizex= p->im2d_settings.sizex;
1625 sizey= p->im2d_settings.sizey;
1626 offsx= p->im2d_settings.offsx;
1627 offsy= p->im2d_settings.offsy;
1629 /* calculate new points */
1630 x0= (short)((pt1->x * sizex) + offsx);
1631 y0= (short)((pt1->y * sizey) + offsy);
1633 x1= (short)((pt2->x * sizex) + offsx);
1634 y1= (short)((pt2->y * sizey) + offsy);
1637 x0= (short)(pt1->x / 1000 * p->sa->winx);
1638 y0= (short)(pt1->y / 1000 * p->sa->winy);
1639 x1= (short)(pt2->x / 1000 * p->sa->winx);
1640 y1= (short)(pt2->y / 1000 * p->sa->winy);
1643 /* check that point segment of the boundbox of the eraser stroke */
1644 if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
1645 /* check if point segment of stroke had anything to do with
1646 * eraser region (either within stroke painted, or on its lines)
1647 * - this assumes that linewidth is irrelevant
1649 if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
1650 /* if function returns true, break this loop (as no more point to check) */
1651 if (gp_stroke_eraser_splitdel(gpf, gps, i))
1659 /* erase strokes which fall under the eraser strokes */
1660 static void gp_stroke_doeraser (tGPsdata *p)
1662 bGPDframe *gpf= p->gpf;
1663 bGPDstroke *gps, *gpn;
1666 /* rect is rectangle of eraser */
1667 rect.xmin= p->mval[0] - p->radius;
1668 rect.ymin= p->mval[1] - p->radius;
1669 rect.xmax= p->mval[0] + p->radius;
1670 rect.ymax= p->mval[1] + p->radius;
1672 /* loop over strokes, checking segments for intersections */
1673 for (gps= gpf->strokes.first; gps; gps= gpn) {
1675 gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
1679 /* ---------- 'Paint' Tool ------------ */
1681 /* init new painting session */
1682 static void gp_session_initpaint (tGPsdata *p)
1684 /* clear previous data (note: is on stack) */
1685 memset(p, 0, sizeof(tGPsdata));
1687 /* make sure the active view (at the starting time) is a 3d-view */
1688 if (curarea == NULL) {
1689 p->status= GP_STATUS_ERROR;
1691 printf("Error: No active view for painting \n");
1694 switch (curarea->spacetype) {
1695 /* supported views first */
1698 View3D *v3d= curarea->spacedata.first;
1700 /* set current area */
1703 /* check that gpencil data is allowed to be drawn */
1704 if ((v3d->flag2 & V3D_DISPGP)==0) {
1705 p->status= GP_STATUS_ERROR;
1707 printf("Error: In active view, Grease Pencil not shown \n");
1714 SpaceNode *snode= curarea->spacedata.first;
1716 /* set current area */
1718 p->v2d= &snode->v2d;
1720 /* check that gpencil data is allowed to be drawn */
1721 if ((snode->flag & SNODE_DISPGP)==0) {
1722 p->status= GP_STATUS_ERROR;
1724 printf("Error: In active view, Grease Pencil not shown \n");
1731 SpaceSeq *sseq= curarea->spacedata.first;
1733 /* set current area */
1737 /* check that gpencil data is allowed to be drawn */
1738 if (sseq->mainb == 0) {
1739 p->status= GP_STATUS_ERROR;
1741 printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil \n");
1744 if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
1745 p->status= GP_STATUS_ERROR;
1747 printf("Error: In active view, Grease Pencil not shown \n");
1754 SpaceImage *sima= curarea->spacedata.first;
1756 /* set the current area */
1759 p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1761 /* check that gpencil data is allowed to be drawn */
1762 if ((sima->flag & SI_DISPGP)==0) {
1763 p->status= GP_STATUS_ERROR;
1765 printf("Error: In active view, Grease Pencil not shown \n");
1770 /* unsupported views */
1773 p->status= GP_STATUS_ERROR;
1775 printf("Error: Active view not appropriate for Grease Pencil drawing \n");
1782 p->gpd= gpencil_data_getactive(p->sa);
1783 if (p->gpd == NULL) {
1786 p->gpd= gpencil_data_addnew();
1787 ok= gpencil_data_setactive(p->sa, p->gpd);
1789 /* most of the time, the following check isn't needed */
1791 /* free gpencil data as it can't be used */
1792 free_gpencil_data(p->gpd);
1794 p->status= GP_STATUS_ERROR;
1796 printf("Error: Could not assign newly created Grease Pencil data to active area \n");
1801 /* set edit flags */
1802 G.f |= G_GREASEPENCIL;
1804 /* clear out buffer (stored in gp-data) in case something contaminated it */
1805 gp_session_validatebuffer(p);
1807 /* set 'default' im2d_settings just in case something that uses this doesn't set it */
1808 p->im2d_settings.sizex= 1;
1809 p->im2d_settings.sizey= 1;
1812 /* cleanup after a painting session */
1813 static void gp_session_cleanup (tGPsdata *p)
1815 bGPdata *gpd= p->gpd;
1817 /* error checking */
1821 /* free stroke buffer */
1823 MEM_freeN(gpd->sbuffer);
1828 gpd->sbuffer_size= 0;
1829 gpd->sbuffer_sflag= 0;
1832 /* init new stroke */
1833 static void gp_paint_initstroke (tGPsdata *p, short paintmode)
1835 /* get active layer (or add a new one if non-existent) */
1836 p->gpl= gpencil_layer_getactive(p->gpd);
1838 p->gpl= gpencil_layer_addnew(p->gpd);
1839 if (p->gpl->flag & GP_LAYER_LOCKED) {
1840 p->status= GP_STATUS_ERROR;
1842 printf("Error: Cannot paint on locked layer \n");
1846 /* get active frame (add a new one if not matching frame) */
1847 p->gpf= gpencil_layer_getframe(p->gpl, CFRA, 1);
1848 if (p->gpf == NULL) {
1849 p->status= GP_STATUS_ERROR;
1851 printf("Error: No frame created (gpencil_paint_init) \n");
1855 p->gpf->flag |= GP_FRAME_PAINT;
1857 /* set 'eraser' for this stroke if using eraser */
1858 p->paintmode= paintmode;
1859 if (p->paintmode == GP_PAINTMODE_ERASER)
1860 p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
1862 /* check if points will need to be made in view-aligned space */
1863 if (p->gpd->flag & GP_DATA_VIEWALIGN) {
1864 switch (p->sa->spacetype) {
1867 float *fp= give_cursor();
1868 initgrabz(fp[0], fp[1], fp[2]);
1870 p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
1875 p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1880 SpaceSeq *sseq= (SpaceSeq *)p->sa->spacedata.first;
1882 float zoom, zoomx, zoomy;
1884 /* set draw 2d-stroke flag */
1885 p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1887 /* calculate zoom factor */
1888 zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom));
1889 if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
1890 zoomx = zoom * ((float)G.scene->r.xasp / (float)G.scene->r.yasp);
1894 zoomx = zoomy = zoom;
1896 /* calculate rect size to use to calculate the size of the drawing area
1897 * - We use the size of the output image not the size of the ibuf being shown
1898 * as it is too messy getting the ibuf (and could be too slow). This should be
1899 * a reasonable for most cases anyway.
1901 rectx= (G.scene->r.size * G.scene->r.xsch) / 100;
1902 recty= (G.scene->r.size * G.scene->r.ysch) / 100;
1904 /* set offset and scale values for opertations to use */
1905 p->im2d_settings.sizex= (int)(zoomx * rectx);
1906 p->im2d_settings.sizey= (int)(zoomy * recty);
1907 p->im2d_settings.offsx= (int)((p->sa->winx-p->im2d_settings.sizex)/2 + sseq->xof);
1908 p->im2d_settings.offsy= (int)((p->sa->winy-p->im2d_settings.sizey)/2 + sseq->yof);
1913 /* check if any ibuf available */
1915 p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1922 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1923 static void gp_paint_strokeend (tGPsdata *p)
1925 /* check if doing eraser or not */
1926 if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
1927 /* smooth stroke before transferring? */
1928 gp_stroke_smooth(p);
1930 /* simplify stroke before transferring? */
1931 gp_stroke_simplify(p);
1933 /* transfer stroke to frame */
1934 gp_stroke_newfrombuffer(p);
1937 /* clean up buffer now */
1938 gp_session_validatebuffer(p);
1941 /* finish off stroke painting operation */
1942 static void gp_paint_cleanup (tGPsdata *p)
1944 /* finish off a stroke */
1945 gp_paint_strokeend(p);
1947 /* "unlock" frame */
1948 p->gpf->flag &= ~GP_FRAME_PAINT;
1950 /* add undo-push so stroke can be undone */
1951 /* FIXME: currently disabled, as it's impossible to get this working nice
1952 * as gpenci data is on currently screen-level (which isn't saved to undo files)
1954 //BIF_undo_push("GPencil Stroke");
1956 /* force redraw after drawing action */
1957 force_draw_plus(SPACE_ACTION, 0);
1962 /* main call to paint a new stroke */
1963 short gpencil_paint (short mousebutton, short paintmode)
1966 short ok = GP_STROKEADD_NORMAL;
1968 /* init paint-data */
1969 gp_session_initpaint(&p);
1970 if (p.status == GP_STATUS_ERROR) {
1971 gp_session_cleanup(&p);
1974 gp_paint_initstroke(&p, paintmode);
1975 if (p.status == GP_STATUS_ERROR) {
1976 gp_session_cleanup(&p);
1980 /* set cursor to indicate drawing */
1981 setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
1983 /* init drawing-device settings */
1984 getmouseco_areawin(p.mval);
1985 p.pressure = get_pressure();
1987 p.mvalo[0]= p.mval[0];
1988 p.mvalo[1]= p.mval[1];
1989 p.opressure= p.pressure;
1991 /* radius for eraser circle is defined in userprefs now */
1992 // TODO: make this more easily tweaked...
1993 p.radius= U.gp_eraser;
1995 /* start drawing eraser-circle (if applicable) */
1996 if (paintmode == GP_PAINTMODE_ERASER)
1997 draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again
1999 /* only allow painting of single 'dots' if:
2000 * - pressure is not excessive (as it can be on some windows tablets)
2001 * - draw-mode for active datablock is turned on
2004 if (paintmode != GP_PAINTMODE_ERASER) {
2005 if (!(p.pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) {
2006 gp_stroke_addpoint(&p, p.mval, p.pressure);
2012 /* get current user input */
2013 getmouseco_areawin(p.mval);
2014 p.pressure = get_pressure();
2016 /* only add current point to buffer if mouse moved (otherwise wait until it does) */
2017 if (paintmode == GP_PAINTMODE_ERASER) {
2018 /* do 'live' erasing now */
2019 gp_stroke_doeraser(&p);
2021 draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0);
2024 p.mvalo[0]= p.mval[0];
2025 p.mvalo[1]= p.mval[1];
2026 p.opressure= p.pressure;
2028 else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) {
2029 /* try to add point */
2030 ok= gp_stroke_addpoint(&p, p.mval, p.pressure);
2032 /* handle errors while adding point */
2033 if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
2034 /* finish off old stroke */
2035 gp_paint_strokeend(&p);
2037 /* start a new stroke, starting from previous point */
2038 gp_stroke_addpoint(&p, p.mvalo, p.opressure);
2039 ok= gp_stroke_addpoint(&p, p.mval, p.pressure);
2041 else if (ok == GP_STROKEADD_INVALID) {
2042 /* the painting operation cannot continue... */
2043 error("Cannot paint stroke");
2044 p.status = GP_STATUS_ERROR;
2047 printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
2052 p.mvalo[0]= p.mval[0];
2053 p.mvalo[1]= p.mval[1];
2054 p.opressure= p.pressure;
2057 BIF_wait_for_statechange();
2059 /* do mouse checking at the end, so don't check twice, and potentially
2062 } while (get_mbut() & mousebutton);
2064 /* clear edit flags */
2065 G.f &= ~G_GREASEPENCIL;
2067 /* restore cursor to indicate end of drawing */
2068 setcursor_space(p.sa->spacetype, CURSOR_STD);
2070 /* check size of buffer before cleanup, to determine if anything happened here */
2071 if (paintmode == GP_PAINTMODE_ERASER) {
2072 ok= 1; /* assume that we did something... */
2073 draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0);
2076 ok= p.gpd->sbuffer_size;
2079 gp_paint_cleanup(&p);
2080 gp_session_cleanup(&p);
2082 /* done! return if a stroke was successfully added */
2087 /* All event (loops) handling checking if stroke drawing should be initiated
2088 * should call this function.
2090 short gpencil_do_paint (ScrArea *sa, short mbut)
2092 bGPdata *gpd = gpencil_data_getactive(sa);
2095 /* check if possible to do painting */
2099 /* currently, we will only 'paint' if:
2100 * 1. draw-mode on gpd is set (for accessibility reasons)
2101 * a) single dots are only available by this method if a single click is made
2102 * b) a straight line is drawn if ctrl-modifier is held (check is done when stroke is converted!)
2103 * 2. if shift-modifier is held + lmb -> 'quick paint'
2107 * draw eraser stroke if:
2108 * 1. using the eraser on a tablet
2109 * 2. draw-mode on gpd is set (for accessiblity reasons)
2110 * (eraser is mapped to right-mouse)
2111 * 3. Alt + 'select' mouse-button
2112 * i.e. if LMB = select: Alt-LMB
2113 * if RMB = select: Alt-RMB
2115 if (get_activedevice() == 2) {
2116 /* eraser on a tablet - always try to erase strokes */
2117 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
2119 else if (gpd->flag & GP_DATA_EDITPAINT) {
2120 /* try to paint/erase */
2121 if (mbut == L_MOUSE)
2122 retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
2123 else if (mbut == R_MOUSE)
2124 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
2126 else if (!(gpd->flag & GP_DATA_LMBPLOCK)) {
2127 /* try to paint/erase as not locked */
2128 if ((G.qual == LR_SHIFTKEY) && (mbut == L_MOUSE)) {
2129 retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW);
2131 else if (G.qual == LR_ALTKEY) {
2132 if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE))
2133 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
2134 else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE))
2135 retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER);
2139 /* return result of trying to paint */
2143 /* ************************************************** */