== Grease Pencil ==
authorJoshua Leung <aligorith@gmail.com>
Tue, 22 Jul 2008 09:53:25 +0000 (09:53 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 22 Jul 2008 09:53:25 +0000 (09:53 +0000)
Grease Pencil is a tool which allows you to draw freehand in some views, allowing you to annotate/scribble over the contents of that view in either 2d or 3d. This facilitates many easier communication and planning abilities.

To use, simply enable it from the View menu (choose 'Grease Pencil...' and click 'Use Grease Pencil'). Then, click+drag using the left-mouse button and the shift-key held to draw a stroke.

For more information, check the following page on the wiki:
http://wiki.blender.org/index.php/User:Aligorith/247_Grease_Pencil

33 files changed:
source/blender/blenkernel/BKE_global.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BDR_drawaction.h
source/blender/include/BDR_gpencil.h [new file with mode: 0644]
source/blender/include/BIF_drawgpencil.h [new file with mode: 0644]
source/blender/include/BIF_editaction.h
source/blender/include/BIF_space.h
source/blender/include/BSE_editaction_types.h
source/blender/include/transform.h
source/blender/makesdna/DNA_action_types.h
source/blender/makesdna/DNA_gpencil_types.h [new file with mode: 0644]
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/src/drawaction.c
source/blender/src/drawgpencil.c [new file with mode: 0644]
source/blender/src/drawnode.c
source/blender/src/drawseq.c
source/blender/src/drawview.c
source/blender/src/editaction.c
source/blender/src/editaction_gpencil.c [new file with mode: 0644]
source/blender/src/editnode.c
source/blender/src/gpencil.c [new file with mode: 0644]
source/blender/src/header_action.c
source/blender/src/header_node.c
source/blender/src/header_seq.c
source/blender/src/header_view3d.c
source/blender/src/interface.c
source/blender/src/space.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c
source/gameengine/Ketsji/KX_BulletPhysicsController.cpp

index 62289d227c762f74a67d3543f208db45a2c89ef4..8c9634cba06051e5df877e3be8ef539bc14497ec 100644 (file)
@@ -175,6 +175,7 @@ typedef struct Global {
 #define G_WEIGHTPAINT  (1 << 15)       
 #define G_TEXTUREPAINT (1 << 16)
 /* #define G_NOFROZEN  (1 << 17) also removed */
+#define G_GREASEPENCIL         (1 << 17)
 #define G_DRAWEDGES            (1 << 18)
 #define G_DRAWCREASES  (1 << 19)
 #define G_DRAWSEAMS     (1 << 20)
@@ -265,3 +266,4 @@ extern Global G;
        
 #endif
 
+
index 3c629818b2dd0204fe899b1804aeeebd584ae36d..090b1d7c6b6a13f283b798d2af5604c83ab37871 100644 (file)
@@ -69,6 +69,7 @@
 #include "DNA_effect_types.h"
 #include "DNA_fileglobal_types.h"
 #include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_image_types.h"
 #include "DNA_key_types.h"
@@ -3698,6 +3699,32 @@ static void lib_link_screen_sequence_ipos(Main *main)
 
 /* ************ READ SCREEN ***************** */
 
+/* relinks grease-pencil data for 3d-view(s) - used for direct_link */
+static void link_gpencil(FileData *fd, bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       bGPDframe *gpf;
+       bGPDstroke *gps;
+       
+       /* relink layers */
+       link_list(fd, &gpd->layers);
+       
+       for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+               /* relink frames */
+               link_list(fd, &gpl->frames);
+               gpl->actframe= newdataadr(fd, gpl->actframe);
+               
+               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                       /* relink strokes (and their points) */
+                       link_list(fd, &gpf->strokes);
+                       
+                       for (gps= gpf->strokes.first; gps; gps= gps->next) {
+                               gps->points= newdataadr(fd, gps->points);
+                       }
+               }
+       }
+}
+
 /* note: file read without screens option G_FILE_NO_UI; 
    check lib pointers in call below */
 static void lib_link_screen(FileData *fd, Main *main)
@@ -3709,23 +3736,23 @@ static void lib_link_screen(FileData *fd, Main *main)
                if(sc->id.flag & LIB_NEEDLINK) {
                        sc->id.us= 1;
                        sc->scene= newlibadr(fd, sc->id.lib, sc->scene);
-
+                       
                        sa= sc->areabase.first;
                        while(sa) {
                                SpaceLink *sl;
-
+                               
                                sa->full= newlibadr(fd, sc->id.lib, sa->full);
-
+                               
                                /* space handler scriptlinks */
                                lib_link_scriptlink(fd, &sc->id, &sa->scriptlink);
-
+                               
                                for (sl= sa->spacedata.first; sl; sl= sl->next) {
                                        if(sl->spacetype==SPACE_VIEW3D) {
                                                View3D *v3d= (View3D*) sl;
-
+                                               
                                                v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
                                                v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
-
+                                               
                                                if(v3d->bgpic) {
                                                        v3d->bgpic->ima= newlibadr_us(fd, sc->id.lib, v3d->bgpic->ima);
                                                }
@@ -4081,6 +4108,10 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
                                v3d->bgpic= newdataadr(fd, v3d->bgpic);
                                if(v3d->bgpic)
                                        v3d->bgpic->iuser.ok= 1;
+                               if(v3d->gpd) {
+                                       v3d->gpd= newdataadr(fd, v3d->gpd);
+                                       link_gpencil(fd, v3d->gpd);
+                               }
                                v3d->localvd= newdataadr(fd, v3d->localvd);
                                v3d->afterdraw.first= v3d->afterdraw.last= NULL;
                                v3d->clipbb= newdataadr(fd, v3d->clipbb);
@@ -4115,9 +4146,30 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
                        }
                        else if(sl->spacetype==SPACE_NODE) {
                                SpaceNode *snode= (SpaceNode *)sl;
+                               
+                               if(snode->gpd) {
+                                       snode->gpd= newdataadr(fd, snode->gpd);
+                                       link_gpencil(fd, snode->gpd);
+                               }
                                snode->nodetree= snode->edittree= NULL;
                                snode->flag |= SNODE_DO_PREVIEW;
                        }
+                       else if(sl->spacetype==SPACE_SEQ) {
+                               SpaceSeq *sseq= (SpaceSeq *)sl;
+                               if(sseq->gpd) {
+                                       sseq->gpd= newdataadr(fd, sseq->gpd);
+                                       link_gpencil(fd, sseq->gpd);
+                               }
+                       }
+                       else if(sl->spacetype==SPACE_ACTION) {
+                               SpaceAction *sact= (SpaceAction *)sl;
+                               
+                               /* WARNING: action-editor doesn't have it's own gpencil data! 
+                                * so only adjust pointer, but DON'T LINK
+                                */
+                               if (sact->gpd) 
+                                       sact->gpd= newdataadr(fd, sact->gpd);
+                       }
                }
 
                sa->v1= newdataadr(fd, sa->v1);
index ca91f1dc3461f7bcd4dc7d33737cde89f0d786ea..b59dd851dfe462b4bcb8e3394a0ca905ff3a2257 100644 (file)
@@ -112,6 +112,7 @@ Important to know is that 'streaming' has been added to files, for Blender Publi
 #include "DNA_customdata_types.h"
 #include "DNA_effect_types.h"
 #include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
 #include "DNA_image_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_fileglobal_types.h"
@@ -1565,6 +1566,32 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
        mywrite(wd, MYWRITE_FLUSH, 0);
 }
 
+static void write_gpencil(WriteData *wd, bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       bGPDframe *gpf;
+       bGPDstroke *gps;
+       
+       /* write gpd data block to file */
+       writestruct(wd, DATA, "bGPdata", 1, gpd);
+       
+       /* write grease-pencil layers to file */
+       for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+               writestruct(wd, DATA, "bGPDlayer", 1, gpl);
+               
+               /* write this layer's frames to file */
+               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                       writestruct(wd, DATA, "bGPDframe", 1, gpf);
+                       
+                       /* write strokes */
+                       for (gps= gpf->strokes.first; gps; gps= gps->next) {
+                               writestruct(wd, DATA, "bGPDstroke", 1, gps);
+                               writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);                               
+                       }
+               }
+       }
+}
+
 static void write_screens(WriteData *wd, ListBase *scrbase)
 {
        bScreen *sc;
@@ -1610,11 +1637,12 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                        sl= sa->spacedata.first;
                        while(sl) {
                                if(sl->spacetype==SPACE_VIEW3D) {
-                                       View3D *v3d= (View3D*) sl;
+                                       View3D *v3d= (View3D *) sl;
                                        writestruct(wd, DATA, "View3D", 1, v3d);
                                        if(v3d->bgpic) writestruct(wd, DATA, "BGpic", 1, v3d->bgpic);
                                        if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
                                        if(v3d->clipbb) writestruct(wd, DATA, "BoundBox", 1, v3d->clipbb);
+                                       if(v3d->gpd) write_gpencil(wd, v3d->gpd);
                                }
                                else if(sl->spacetype==SPACE_IPO) {
                                        writestruct(wd, DATA, "SpaceIpo", 1, sl);
@@ -1626,7 +1654,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                                        writestruct(wd, DATA, "SpaceFile", 1, sl);
                                }
                                else if(sl->spacetype==SPACE_SEQ) {
+                                       SpaceSeq *sseq= (SpaceSeq *)sl;
                                        writestruct(wd, DATA, "SpaceSeq", 1, sl);
+                                       if(sseq->gpd) write_gpencil(wd, sseq->gpd);
                                }
                                else if(sl->spacetype==SPACE_OOPS) {
                                        SpaceOops *so= (SpaceOops *)sl;
@@ -1689,7 +1719,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                                        writestruct(wd, DATA, "SpaceTime", 1, sl);
                                }
                                else if(sl->spacetype==SPACE_NODE){
+                                       SpaceNode *snode= (SpaceNode *)sl;
                                        writestruct(wd, DATA, "SpaceNode", 1, sl);
+                                       if(snode->gpd) write_gpencil(wd, snode->gpd);
                                }
                                sl= sl->next;
                        }
index 91635123cb7e1642a805e4bc6ea2c147c4181c39..7cb0768e83250d45b28b907cde89a994d4992179 100644 (file)
@@ -38,6 +38,7 @@ struct bAction;
 struct bActionGroup;
 struct Object;
 struct ListBase;
+struct bGPDlayer;
 
 /* ****************************** Base Structs ****************************** */
 
@@ -82,6 +83,7 @@ void draw_ipo_channel(struct gla2DDrawInfo *di, struct Ipo *ipo, float ypos);
 void draw_agroup_channel(struct gla2DDrawInfo *di, struct bActionGroup *agrp, float ypos);
 void draw_action_channel(struct gla2DDrawInfo *di, struct bAction *act, float ypos);
 void draw_object_channel(struct gla2DDrawInfo *di, struct Object *ob, float ypos);
+void draw_gpl_channel(struct gla2DDrawInfo *di, struct bGPDlayer *gpl, float ypos);
 
 /* Keydata Generation */
 void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
@@ -89,6 +91,7 @@ void ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks, ActKeysIn
 void agroup_to_keylist(struct bActionGroup *agrp, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
 void action_to_keylist(struct bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
 void ob_to_keylist(struct Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
+void gpl_to_keylist(struct bGPDlayer *gpl, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
 
 #endif  /*  BDR_DRAWACTION_H */
 
diff --git a/source/blender/include/BDR_gpencil.h b/source/blender/include/BDR_gpencil.h
new file mode 100644 (file)
index 0000000..d0ebd09
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * $Id: BDR_gpencil.h 14444 2008-04-16 22:40:48Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_GPENCIL_H
+#define BDR_GPENCIL_H
+
+struct ListBase;
+struct bScreen;
+struct ScrArea;
+struct View3D;
+struct SpaceNode;
+struct SpaceSeq;
+struct bGPdata;
+struct bGPDlayer;
+struct bGPDframe;
+
+/* ------------ Grease-Pencil API ------------------ */
+
+void free_gpencil_strokes(struct bGPDframe *gpf);
+void free_gpencil_frames(struct bGPDlayer *gpl);
+void free_gpencil_layers(struct ListBase *list);
+void free_gpencil_data(struct bGPdata *gpd);
+
+struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd);
+struct bGPdata *gpencil_data_addnew(void);
+
+struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd);
+
+struct bGPdata *gpencil_data_getactive(struct ScrArea *sa);
+short gpencil_data_setactive(struct ScrArea *sa, struct bGPdata *gpd);
+struct bGPdata *gpencil_data_getetime(struct bScreen *sc);
+void gpencil_data_setetime(struct bScreen *sc, struct bGPdata *gpd);
+
+void gpencil_frame_delete_laststroke(struct bGPDframe *gpf);
+
+struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, short addnew);
+void gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
+void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
+void gpencil_layer_delactive(struct bGPdata *gpd);
+
+void gpencil_delete_actframe(struct bGPdata *gpd);
+void gpencil_delete_laststroke(struct bGPdata *gpd);
+
+void gpencil_delete_operation(short mode);
+void gpencil_delete_menu(void);
+
+//short gpencil_paint(short mousebutton);
+short gpencil_do_paint(struct ScrArea *sa);
+
+#endif /*  BDR_GPENCIL_H */
diff --git a/source/blender/include/BIF_drawgpencil.h b/source/blender/include/BIF_drawgpencil.h
new file mode 100644 (file)
index 0000000..4184463
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * $Id: BIF_drawgpencil.h 14444 2008-04-16 22:40:48Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWGPENCIL_H
+#define BIF_DRAWGPENCIL_H
+
+struct ScrArea;
+struct View3D;
+struct SpaceNode;
+struct SpaceSeq;
+struct bGPdata;
+struct uiBlock;
+
+short draw_gpencil_panel(struct uiBlock *block, struct bGPdata *gpd, struct ScrArea *sa); 
+
+void draw_gpencil_2dview(struct ScrArea *sa, short onlyv2d);
+void draw_gpencil_3dview(struct ScrArea *sa, short only3d);
+void draw_gpencil_oglrender(struct View3D *v3d, int winx, int winy);
+
+#endif /*  BIF_DRAWGPENCIL_H */ 
index 7e0f703681b4aec57c1a7b34323d450aa8c2e7dd..9f6751daeffd73ef1ee6cd7832dc57320785738a 100644 (file)
@@ -48,7 +48,8 @@ enum {
        ACTTYPE_FILLIPO,
        ACTTYPE_FILLCON,
        ACTTYPE_IPO,
-       ACTTYPE_SHAPEKEY
+       ACTTYPE_SHAPEKEY,
+       ACTTYPE_GPLAYER
 };
 
 /* Macros for easier/more consistant state testing */
@@ -69,7 +70,10 @@ enum {
 #define EDITABLE_ICU(icu) ((icu->flag & IPO_PROTECT)==0)
 #define SEL_ICU(icu) (icu->flag & IPO_SELECT)
 
-#define NLA_ACTION_SCALED (G.saction->pin==0 && OBACT && OBACT->action)
+#define EDITABLE_GPL(gpl) ((gpl->flag & GP_LAYER_LOCKED)==0)
+#define SEL_GPL(gpl) ((gpl->flag & GP_LAYER_ACTIVE) || (gpl->flag & GP_LAYER_SELECT))
+
+#define NLA_ACTION_SCALED (G.saction->mode==SACTCONT_ACTION && G.saction->pin==0 && OBACT && OBACT->action)
 #define NLA_IPO_SCALED (OBACT && OBACT->action && G.sipo->pin==0 && G.sipo->actname)
 
 /* constants for setting ipo-interpolation type */
@@ -114,6 +118,8 @@ struct BWinEvent;
 struct Key;
 struct ListBase;
 struct TimeMarker;
+struct bGPdata;
+struct bGPDlayer;
 
 /* Key operations */
 void transform_action_keys(int mode, int dummy);
@@ -176,6 +182,24 @@ void action_add_localmarker(struct bAction *act, int frame);
 void action_rename_localmarker(struct bAction *act);
 void action_remove_localmarkers(struct bAction *act);
 
+/* Grease-Pencil Data */
+void gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, short onlysel);
+
+void deselect_gpencil_layers(struct bGPdata *gpd, short select_mode);
+
+short is_gplayer_frame_selected(struct bGPDlayer *gpl);
+void set_gplayer_frame_selection(struct bGPDlayer *gpl, short mode);
+void select_gpencil_frames(struct bGPDlayer *gpl, short select_mode);
+void select_gpencil_frame(struct bGPDlayer *gpl, int selx, short select_mode);
+void borderselect_gplayer_frames(struct bGPDlayer *gpl, float min, float max, short select_mode);
+
+void delete_gpencil_layers(void);
+void delete_gplayer_frames(struct bGPDlayer *gpl);
+void duplicate_gplayer_frames(struct bGPDlayer *gpd);
+
+void snap_gplayer_frames(struct bGPDlayer *gpl, short mode);
+void mirror_gplayer_frames(struct bGPDlayer *gpl, short mode);
+
 /* ShapeKey stuff */
 struct Key *get_action_mesh_key(void);
 int get_nearest_key_num(struct Key *key, short *mval, float *x);
index 37be4a9eafc5c29b8cf7afd1bdd4aae8d40e8d6a..4b2b8e14bb63da606ca3ce8c399d307805ab41be 100644 (file)
@@ -53,6 +53,7 @@ struct SpaceOops;
 #define VIEW3D_HANDLER_PREVIEW         4
 #define VIEW3D_HANDLER_MULTIRES         5
 #define VIEW3D_HANDLER_TRANSFORM       6
+#define VIEW3D_HANDLER_GREASEPENCIL 7
 
 /* ipo handler codes */
 #define IPO_HANDLER_PROPERTIES 20
@@ -73,11 +74,15 @@ struct SpaceOops;
 #define NLA_HANDLER_PROPERTIES 50
 
 /* sequence handler codes */
-#define SEQ_HANDLER_PROPERTIES 60
+#define SEQ_HANDLER_PROPERTIES         60
+#define SEQ_HANDLER_GREASEPENCIL       61
 
 /* imasel handler codes */
 #define IMASEL_HANDLER_IMAGE   70
 
+/* nodes handler codes */
+#define NODES_HANDLER_GREASEPENCIL             80
+
 /* theme codes */
 #define B_ADD_THEME    3301
 #define B_DEL_THEME    3302
@@ -145,3 +150,4 @@ extern               void mainwindow_close(void);
 
 #endif
 
+
index c531383accc8b684b86494136976909c222e9599..be21041597312e29c08f741b02a95e10ef5bebdf 100644 (file)
@@ -38,7 +38,8 @@ typedef enum ALE_KEYTYPE {
        ALE_NONE = 0,
        ALE_IPO,        
        ALE_ICU,
-       ALE_GROUP       
+       ALE_GROUP,
+       ALE_GPFRAME,
 } ALE_KEYTYPE;
 
 /* This struct defines a structure used for quick access */
@@ -78,7 +79,8 @@ typedef enum ACTFILTER_FLAGS {
 typedef enum ACTCONT_TYPES {
        ACTCONT_NONE = 0,
        ACTCONT_ACTION,
-       ACTCONT_SHAPEKEY
+       ACTCONT_SHAPEKEY,
+       ACTCONT_GPENCIL
 } ACTCONT_TYPES;
 
 #endif
index 4e3b80134f9e2487c1daa7188127dbd87727b172..720b856a14941e9c31a5ab7911f1960631d88c0d 100644 (file)
@@ -397,6 +397,7 @@ int Align(TransInfo *t, short mval[2]);
 
 /*********************** transform_conversions.c ********** */
 struct ListBase;
+void flushTransGPactionData(TransInfo *t);
 void flushTransIpoData(TransInfo *t);
 void flushTransUVs(TransInfo *t);
 void flushTransParticles(TransInfo *t);
index 18d2a1cb6f3a61c32497ce67855ec007d8253b0d..d7969a7379b19211f42cdcc59d46d8cf2284ef5a 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "DNA_listBase.h"
 #include "DNA_ID.h"
+#include "DNA_gpencil_types.h"
 #include "DNA_view2d_types.h"
 #include "DNA_userdef_types.h"
 
@@ -183,8 +184,11 @@ typedef struct SpaceAction {
        View2D v2d;     
        
        bAction         *action;                /* the currently active action */
-       short flag, autosnap;           /* flag: bitmapped settings; autosnap: automatic keyframe snapping mode */
-       short pin, actnr, lock;         /* pin: keep showing current action; actnr: used for finding chosen action from menu; lock: lock time to other windows */
+       bGPdata         *gpd;           /* the currently active gpencil block (for editing) */
+       
+       char  mode, autosnap;           /* mode: editing context; autosnap: automatic keyframe snapping mode   */
+       short flag, actnr;                      /* flag: bitmapped settings; */
+       short pin, lock;                        /* pin: keep showing current action; actnr: used for finding chosen action from menu; lock: lock time to other windows */
        short actwidth;                         /* width of the left-hand side name panel (in pixels?) */
        float timeslide;                        /* for Time-Slide transform mode drawing - current frame? */
 } SpaceAction;
@@ -238,6 +242,18 @@ typedef enum SACTION_FLAG {
        SACTION_NODRAWGCOLORS = (1<<7)
 } SACTION_FLAG;        
 
+/* SpaceAction Mode Settings */
+typedef enum SACTCONT_MODES {
+               /* action (default) */
+       SACTCONT_ACTION = 0,
+               /* editing of shapekey's IPO block */
+       SACTCONT_SHAPEKEY,
+               /* editing of gpencil data */
+       SACTCONT_GPENCIL,
+               /* dopesheet (unimplemented... future idea?) */
+       SACTCONT_DOPESHEET
+} SACTCONTEXT_MODES;
+
 /* SpaceAction AutoSnap Settings (also used by SpaceNLA) */
 typedef enum SACTSNAP_MODES {
                /* no auto-snap */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
new file mode 100644 (file)
index 0000000..eafd886
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * $Id: DNA_gpencil_types.h 8768 2006-11-07 00:10:37Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation.
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef DNA_GPENCIL_TYPES_H
+#define DNA_GPENCIL_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+/* Grease-Pencil Annotations - 'Stroke Point'
+ *     -> Coordinates may either be 2d or 3d depending on settings at the time
+ *     -> Coordinates of point on stroke, in proportions of window size
+ *             (i.e. n/1000). This assumes that the bottom-left corner is (0,0)
+ */
+typedef struct bGPDspoint {
+       float x, y, z;                  /* co-ordinates of point (usually 2d, but can be 3d as well) */                         
+       float pressure;                 /* pressure of input device (from 0 to 1) at this point */
+} bGPDspoint;
+
+/* Grease-Pencil Annotations - 'Stroke'
+ *     -> A stroke represents a (simplified version) of the curve
+ *        drawn by the user in one 'mousedown'->'mouseup' operation
+ */
+typedef struct bGPDstroke {
+       struct bGPDstroke *next, *prev;
+       
+       bGPDspoint *points;             /* array of data-points for stroke */
+       int totpoints;                  /* number of data-points in array */
+       
+       short thickness;                /* thickness of stroke (currently not used) */  
+       short flag;                             /* various settings about this stroke */
+} bGPDstroke;
+
+/* bGPDstroke->flag */
+       /* stroke is in 3d-space */
+#define GP_STROKE_3DSPACE              (1<<0)
+       /* stroke is in 2d-space */
+#define GP_STROKE_2DSPACE              (1<<1)
+
+
+/* Grease-Pencil Annotations - 'Frame'
+ *     -> Acts as storage for the 'image' formed by strokes
+ */
+typedef struct bGPDframe {
+       struct bGPDframe *next, *prev;
+       
+       ListBase strokes;       /* list of the simplified 'strokes' that make up the frame's data */
+       
+       int framenum;           /* frame number of this frame */
+       int flag;                       /* temp settings */
+} bGPDframe;
+
+/* bGPDframe->flag */  
+       /* frame is being painted on */
+#define GP_FRAME_PAINT         (1<<0)
+       /* for editing in Action Editor */
+#define GP_FRAME_SELECT                (1<<1)
+
+
+/* Grease-Pencil Annotations - 'Layer' */
+typedef struct bGPDlayer {
+       struct bGPDlayer *next, *prev;
+       
+       ListBase frames;                /* list of annotations to display for frames (bGPDframe list) */
+       bGPDframe *actframe;    /* active frame (should be the frame that is currently being displayed) */
+       
+       int flag;                               /* settings for layer */                
+       short thickness;                /* current thickness to apply to strokes */
+       short gstep;                    /* max number of frames between active and ghost to show (0=only those on either side) */
+       
+       float color[4];                 /* color that should be used to draw all the strokes in this layer */
+       
+       char info[128];                 /* optional reference info about this layer (i.e. "director's comments, 12/3") */
+} bGPDlayer;
+
+/* bGPDlayer->flag */
+       /* don't display layer */
+#define GP_LAYER_HIDE          (1<<0)
+       /* protected from further editing */
+#define GP_LAYER_LOCKED                (1<<1)  
+       /* layer is 'active' layer being edited */
+#define GP_LAYER_ACTIVE                (1<<2)
+       /* draw points of stroke for debugging purposes */
+#define GP_LAYER_DRAWDEBUG     (1<<3)
+       /* do onionskinning */
+#define GP_LAYER_ONIONSKIN     (1<<4)
+       /* for editing in Action Editor */
+#define GP_LAYER_SELECT                (1<<5)
+
+
+/* Grease-Pencil Annotations - 'DataBlock' */
+typedef struct bGPdata {
+       /* saved Grease-Pencil data */
+       ListBase layers;                /* bGPDlayers */
+       int flag;                               /* settings for this datablock */
+       
+       /* not-saved stroke buffer data (only used during paint-session) 
+        *      - buffer must be initialised before use, but freed after 
+        *        whole paint operation is over
+        */
+       short sbuffer_size;                     /* number of elements currently in cache */
+       short sbuffer_sflag;            /* flags for stroke that cache represents */
+       bGPDspoint *sbuffer;            /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
+} bGPdata;
+
+/* bGPdata->flag */
+       /* draw this datablock's data (not used) */
+#define GP_DATA_DISP           (1<<0)
+       /* show debugging info in viewport (i.e. status print) */
+#define GP_DATA_DISPINFO       (1<<1)
+       /* is the block being shown in Action Editor */
+#define GP_DATA_EDITTIME       (1<<2)
+       /* is the block overriding all clicks? */
+#define GP_DATA_EDITPAINT      (1<<3)
+       /* new strokes are added in viewport space */
+#define GP_DATA_VIEWALIGN      (1<<4)
+
+#endif /*  DNA_GPENCIL_TYPES_H */
index bc30a12ff274da92425398eeb4a5f83a4bce105f..a8694dfb7f59a9487c7c9a535ff89d708b9ba40c 100644 (file)
@@ -50,6 +50,7 @@ struct RenderInfo;
 struct bNodeTree;
 struct uiBlock;
 struct FileList;
+struct bGPdata;
 
        /**
         * The base structure all the other spaces
@@ -150,6 +151,8 @@ typedef struct SpaceSeq {
        short zebra;
        int flag;
        float zoom;
+       
+       struct bGPdata *gpd;            /* grease-pencil data */
 } SpaceSeq;
 
 typedef struct SpaceFile {
@@ -339,6 +342,8 @@ typedef struct SpaceNode {
        float blockscale;
        struct ScrArea *area;
        
+       short blockhandler[8];
+       
        View2D v2d;
        
        struct ID *id, *from;           /* context, no need to save in file? well... pinning... */
@@ -351,11 +356,13 @@ typedef struct SpaceNode {
        struct bNodeTree *nodetree, *edittree;
        int treetype, pad;                      /* treetype: as same nodetree->type */
        
+       struct bGPdata *gpd;            /* grease-pencil data */
 } SpaceNode;
 
 /* snode->flag */
 #define SNODE_DO_PREVIEW       1
 #define SNODE_BACKDRAW         2
+#define SNODE_DISPGP           4
 
 typedef struct SpaceImaSel {
        SpaceLink *next, *prev;
@@ -657,6 +664,7 @@ typedef struct SpaceImaSel {
 #define SEQ_MARKER_TRANS 2
 #define SEQ_DRAW_COLOR_SEPERATED     4
 #define SEQ_DRAW_SAFE_MARGINS        8
+#define SEQ_DRAW_GPENCIL                       16
 
 /* space types, moved from DNA_screen_types.h */
 enum {
index c21d629be831668c58c88fe549016dc07b2854dc..135272b9ac244dc1433fe2aa8829fc9e0b5d0061 100644 (file)
@@ -40,6 +40,7 @@ struct Base;
 struct BoundBox;
 struct RenderInfo;
 struct RetopoViewData;
+struct bGPdata;
 
 /* This is needed to not let VC choke on near and far... old
  * proprietary MS extensions... */
@@ -53,9 +54,12 @@ struct RetopoViewData;
 #include "DNA_listBase.h"
 #include "DNA_image_types.h"
 
+/* ******************************** */
+
 /* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the
  * code, and patch for windows. */
-
+/* Background Picture in 3D-View */
 typedef struct BGpic {
     struct Image *ima;
        struct ImageUser iuser;
@@ -63,6 +67,9 @@ typedef struct BGpic {
     short xim, yim;
 } BGpic;
 
+/* ********************************* */
+
+/* 3D ViewPort Struct */
 typedef struct View3D {
        struct SpaceLink *next, *prev;
        int spacetype;
@@ -135,9 +142,10 @@ typedef struct View3D {
        char ndoffilter;                /*filter for 6DOF devices 0 normal, 1 dominant */
        
        void *properties_storage;       /* Nkey panel stores stuff here, not in file */
-
+       struct bGPdata *gpd;            /* Grease-Pencil Data (annotation layers) */
 } View3D;
 
+
 /* View3D->flag (short) */
 #define V3D_MODE                       (16+32+64+128+256+512)
 #define V3D_DISPIMAGE          1
@@ -158,10 +166,12 @@ typedef struct View3D {
 #define V3D_DRAW_CENTERS       32768
 
 /* View3d->flag2 (short) */
+#define V3D_MODE2                      (32)
 #define V3D_OPP_DIRECTION_NAME 1
 #define V3D_FLYMODE                            2
 #define V3D_DEPRECATED                 4 /* V3D_TRANSFORM_SNAP, moved to a scene setting */
 #define V3D_SOLID_TEX                  8
+#define V3D_DISPGP                             16
 
 /* View3D->around */
 #define V3D_CENTER              0
@@ -203,3 +213,4 @@ typedef struct View3D {
 
 #endif
 
+
index 83f4e633fa1670303de53f430d3ebbe1e1eb7e18..3818d66b39ca96ba42b0f966ada09a1a523c2c21 100644 (file)
@@ -126,6 +126,7 @@ char *includefiles[] = {
        "DNA_customdata_types.h",
        "DNA_particle_types.h",
        "DNA_cloth_types.h",
+       "DNA_gpencil_types.h",
        // if you add files here, please add them at the end
        // of makesdna.c (this file) as well
 
@@ -1147,4 +1148,5 @@ int main(int argc, char ** argv)
 #include "DNA_customdata_types.h"
 #include "DNA_particle_types.h"
 #include "DNA_cloth_types.h"
+#include "DNA_gpencil_types.h"
 /* end of list */
index 6fe37c1c6e50b569773ba527b55ce448d97d9982..9b1af3f1a065b7eb588a01ed07d4693435528c3a 100644 (file)
@@ -58,6 +58,7 @@
 #include "DNA_constraint_types.h"
 #include "DNA_key_types.h"
 #include "DNA_userdef_types.h"
+#include "DNA_gpencil_types.h"
 
 #include "BKE_action.h"
 #include "BKE_depsgraph.h"
@@ -74,6 +75,7 @@
 #include "BIF_editnla.h"
 #include "BIF_interface.h"
 #include "BIF_interface_icons.h"
+#include "BIF_drawgpencil.h"
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 #include "BIF_resources.h"
@@ -83,6 +85,7 @@
 
 #include "BDR_drawaction.h"
 #include "BDR_editcurve.h"
+#include "BDR_gpencil.h"
 
 #include "BSE_drawnla.h"
 #include "BSE_drawipo.h"
@@ -622,6 +625,28 @@ static void draw_channel_names(void)
                                        sprintf(name, "Constraint");
                                }
                                        break;
+                               case ACTTYPE_GPLAYER: /* gpencil layer */
+                               {
+                                       bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                                       
+                                       indent = 0;
+                                       special = -1;
+                                       expand = -1;
+                                               
+                                       if (EDITABLE_GPL(gpl))
+                                               protect = ICON_UNLOCKED;
+                                       else
+                                               protect = ICON_LOCKED;
+                                               
+                                       if (gpl->flag & GP_LAYER_HIDE)
+                                               mute = ICON_MUTE_IPO_ON;
+                                       else
+                                               mute = ICON_MUTE_IPO_OFF;
+                                       
+                                       sel = SEL_GPL(gpl);
+                                       BLI_snprintf(name, 32, gpl->info);
+                               }
+                                       break;
                        }       
 
                        /* now, start drawing based on this information */
@@ -827,6 +852,12 @@ static void draw_channel_strips(void)
                                        sel = SEL_ICU(icu);
                                }
                                        break;
+                               case ACTTYPE_GPLAYER:
+                               {
+                                       bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                                       sel = SEL_GPL(gpl);
+                               }
+                                       break;
                        }
                        
                        if (datatype == ACTCONT_ACTION) {
@@ -865,6 +896,19 @@ static void draw_channel_strips(void)
                                glColor4ub(col2[0], col2[1], col2[2], 0x44);
                                glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax,  channel_y+CHANNELHEIGHT/2);
                        }
+                       else if (datatype == ACTCONT_GPENCIL) {
+                               gla2DDrawTranslatePt(di, G.v2d->cur.xmin, y, &frame1_x, &channel_y);
+                               
+                               /* frames less than one get less saturated background */
+                               if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+                               else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+                               glRectf(0, channel_y-CHANNELHEIGHT/2, frame1_x, channel_y+CHANNELHEIGHT/2);
+                               
+                               /* frames one and higher get a saturated background */
+                               if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
+                               else glColor4ub(col2[0], col2[1], col2[2], 0x44);
+                               glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax,  channel_y+CHANNELHEIGHT/2);
+                       }
                }
                
                /*      Increment the step */
@@ -899,6 +943,9 @@ static void draw_channel_strips(void)
                                case ALE_ICU:
                                        draw_icu_channel(di, ale->key_data, y);
                                        break;
+                               case ALE_GPFRAME:
+                                       draw_gpl_channel(di, ale->data, y);
+                                       break;
                        }
                }
                
@@ -1075,6 +1122,7 @@ void drawactionspace(ScrArea *sa, void *spacedata)
 {
        bAction *act = NULL;
        Key *key = NULL;
+       bGPdata *gpd = NULL;
        void *data;
        short datatype;
        
@@ -1090,18 +1138,38 @@ void drawactionspace(ScrArea *sa, void *spacedata)
 
        /* only try to refresh action that's displayed if not pinned */
        if (G.saction->pin==0) {
-               if (OBACT)
-                       G.saction->action = OBACT->action;
-               else
-                       G.saction->action= NULL;
+               /* depends on mode */
+               switch (G.saction->mode) {
+                       case SACTCONT_ACTION:
+                       {
+                               if (OBACT)
+                                       G.saction->action = OBACT->action;
+                               else
+                                       G.saction->action= NULL;
+                       }
+                               break;
+                       case SACTCONT_GPENCIL:
+                       {
+                               /* this searching could be slow (so users should pin after this is found) */
+                               G.saction->gpd= gpencil_data_getetime(G.curscreen);
+                       }
+                               break;
+               }
        }
        
        /* get data */
        data = get_action_context(&datatype);
-       if (datatype == ACTCONT_ACTION)
-               act = data;
-       else if (datatype == ACTCONT_SHAPEKEY)
-               key = data;
+       switch (datatype) {
+               case ACTCONT_ACTION:
+                       act = data;
+                       break;
+               case ACTCONT_SHAPEKEY:
+                       key = data;
+                       break;
+               case ACTCONT_GPENCIL:
+                       gpd = data;
+                       break;
+       }
        
        /* Lets make sure the width of the left hand of the screen
         * is set to an appropriate value based on whether sliders
@@ -1450,10 +1518,15 @@ static ActKeysInc *init_aki_data()
        static ActKeysInc aki;
        
        /* init data of static struct here */
-       if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED)
+       if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED &&
+               (G.saction->mode == SACTCONT_ACTION))
+       {
                aki.ob= OBACT;
+       }
        else if (curarea->spacetype == SPACE_NLA)
+       {
                aki.ob= NULL; // FIXME
+       }
        else
                aki.ob= NULL;
                
@@ -1528,6 +1601,16 @@ void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
        BLI_freelistN(&keys);
 }
 
+void draw_gpl_channel(gla2DDrawInfo *di, bGPDlayer *gpl, float ypos)
+{
+       ListBase keys = {0, 0};
+       ActKeysInc *aki = init_aki_data();
+       
+       gpl_to_keylist(gpl, &keys, NULL, aki);
+       draw_keylist(di, &keys, NULL, ypos);
+       BLI_freelistN(&keys);
+}
+
 /* --------------- Conversion: data -> keyframe list ------------------ */
 
 void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
@@ -1674,3 +1757,26 @@ void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks, ActKeysIn
        }
 }
 
+void gpl_to_keylist(bGPDlayer *gpl, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
+{
+       bGPDframe *gpf;
+       ActKeyColumn *ak;
+       
+       if (gpl && keys) {
+               /* loop over frames, converting directly to 'keyframes' (should be in order too) */
+               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                       ak= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
+                       BLI_addtail(keys, ak);
+                       
+                       ak->cfra= gpf->framenum;
+                       ak->modified = 1;
+                       ak->handle_type= 0; 
+                       
+                       if (gpf->flag & GP_FRAME_SELECT)
+                               ak->sel = SELECT;
+                       else
+                               ak->sel = 0;
+               }
+       }
+}
+
diff --git a/source/blender/src/drawgpencil.c b/source/blender/src/drawgpencil.c
new file mode 100644 (file)
index 0000000..55d0464
--- /dev/null
@@ -0,0 +1,653 @@
+/**
+ * $Id: drawgpencil.c 14881 2008-05-18 10:41:42Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_butspace.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_toets.h"
+
+#include "BDR_gpencil.h"
+#include "BIF_drawgpencil.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+#include "butspace.h"
+
+#include "PIL_time.h"                  /* sleep                                */
+#include "mydevice.h"
+
+/* ************************************************** */
+/* GREASE PENCIL PANEL-UI DRAWING */
+
+/* Every space which implements Grease-Pencil functionality should have a panel
+ * for the settings. All of the space-dependent parts should be coded in the panel
+ * code for that space, but the rest is all handled by generic panel here.
+ */
+
+/* ------- Callbacks ----------- */
+/* These are just 'dummy wrappers' around gpencil api calls */
+
+/* make layer active one after being clicked on */
+void gp_ui_activelayer_cb (void *gpd, void *gpl)
+{
+       gpencil_layer_setactive(gpd, gpl);
+}
+
+/* rename layer and set active */
+void gp_ui_renamelayer_cb (void *gpd_arg, void *gpl_arg)
+{
+       bGPdata *gpd= (bGPdata *)gpd_arg;
+       bGPDlayer *gpl= (bGPDlayer *)gpl_arg;
+       
+       BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
+       gpencil_layer_setactive(gpd, gpl);
+}
+
+/* add a new layer */
+void gp_ui_addlayer_cb (void *gpd, void *dummy)
+{
+       gpencil_layer_addnew(gpd);
+}
+
+/* delete active layer */
+void gp_ui_dellayer_cb (void *gpd, void *dummy)
+{
+       gpencil_layer_delactive(gpd);
+}
+
+/* delete last stroke of active layer */
+void gp_ui_delstroke_cb (void *gpd, void *gpl)
+{
+       bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+       
+       gpencil_layer_setactive(gpd, gpl);
+       gpencil_frame_delete_laststroke(gpf);
+}
+
+/* delete active frame of active layer */
+void gp_ui_delframe_cb (void *gpd, void *gpl)
+{
+       bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+       
+       gpencil_layer_setactive(gpd, gpl);
+       gpencil_layer_delframe(gpl, gpf);
+}
+
+
+/* set this set of gpencil data for editing in action editor */
+void gp_ui_dotime_cb (void *gpd_arg, void *dummy)
+{
+       bGPdata *gpd= (bGPdata *)gpd_arg;
+       
+       /* check if setting or clearing (note: setting was just set...) */
+       if (gpd->flag & GP_DATA_EDITTIME)
+               gpencil_data_setetime(G.curscreen, gpd);
+       else    
+               gpencil_data_setetime(G.curscreen, NULL);
+}
+
+
+/* ------- Drawing Code ------- */
+
+/* draw the controls for a given layer */
+static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short *xco, short *yco)
+{
+       uiBut *but;
+       short width= 314;
+       short height;
+       int rb_col;
+       
+       /* unless button has own callback, it adds this callback to button */
+       uiBlockSetFunc(block, gp_ui_activelayer_cb, gpd, gpl);
+       
+       /* draw header */
+       {
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               
+               /* rounded header */
+               rb_col= (gpl->flag & GP_LAYER_ACTIVE)?50:20;
+               uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15 , rb_col-20, ""); 
+               
+               /* lock toggle */
+               uiDefIconButBitI(block, ICONTOG, GP_LAYER_LOCKED, B_REDR, ICON_UNLOCKED,        *xco-7, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Layer cannot be modified");
+       }
+       
+       /* when layer is locked or hidden, don't draw the rest of its settings */
+       if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) {
+               height= 26;
+               
+               /* draw rest of header */
+               {
+                       /* visibility button (only if hidden but not locked!) */
+                       if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
+                               uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
+                       
+                       /* name */
+                       uiDefBut(block, LABEL, 1, gpl->info,    *xco+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "Short description of what this layer is for (optional)");
+               }
+               
+               /* draw backdrop */
+               uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
+               
+               /* draw settings... (i.e. just warning for this one) */
+               if (gpl->flag & GP_LAYER_HIDE)
+                       uiDefBut(block, LABEL, 1, "Grease Pencil Layer Hidden", *xco+60, *yco-26, 205, 20, NULL, 0.0, 0.0, 0, 0, "");
+               else
+                       uiDefBut(block, LABEL, 1, "Grease Pencil Layer Locked", *xco+60, *yco-26, 205, 20, NULL, 0.0, 0.0, 0, 0, "");
+                       
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+       else {
+               height= 100;
+               
+               /* draw rest of header */
+               {
+                       /* visibility button */
+                       uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
+                       
+                       uiBlockSetEmboss(block, UI_EMBOSS);
+                       
+                       /* name */
+                       but= uiDefButC(block, TEX, B_REDR, "Info:",     *xco+35, *yco, 240, 20, gpl->info, 0, 127, 0, 0, "Short description of what this layer is for (optional)");
+                       uiButSetFunc(but, gp_ui_renamelayer_cb, gpd, gpl);
+                       
+                       /* delete 'button' */
+                       uiBlockSetEmboss(block, UI_EMBOSSN);
+                       
+                       but= uiDefIconBut(block, BUT, B_REDR, ICON_X, *xco+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete layer");
+                       uiButSetFunc(but, gp_ui_dellayer_cb, gpd, NULL);
+                       
+                       uiBlockSetEmboss(block, UI_EMBOSS);
+               }
+               
+               /* draw backdrop */
+               uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
+               
+               /* draw settings */
+               {
+                       /* color */
+                       uiBlockBeginAlign(block);
+                               uiDefButF(block, COL, B_REDR, "",               *xco, *yco-26, 150, 19, gpl->color, 0, 0, 0, 0, "Color to use for all strokes on this Grease Pencil Layer");
+                               uiDefButF(block, NUMSLI, B_REDR, "Opacity: ",           *xco,*yco-45,150,19, &gpl->color[3], 0.3, 1.0, 0, 0, "Visibility of stroke (0.3 to 1.0)");
+                       uiBlockEndAlign(block);
+                       
+                       /* stroke thickness */
+                       uiDefButS(block, NUMSLI, B_REDR, "Thickness:",  *xco, *yco-75, 150, 20, &gpl->thickness, 1, 10, 0, 0, "Thickness of strokes (in pixels)");
+                       
+                       
+                       /* onion-skinning */
+                       uiBlockBeginAlign(block);
+                               uiDefButBitI(block, TOG, GP_LAYER_ONIONSKIN, B_REDR, "Onion-Skin", *xco+160, *yco-26, 140, 20, &gpl->flag, 0, 0, 0, 0, "Ghost frames on either side of frame");
+                               uiDefButS(block, NUMSLI, B_REDR, "GStep:",      *xco+160, *yco-46, 140, 20, &gpl->gstep, 0, 120, 0, 0, "Maximum frame range on either side of active frame to show (0 = just 'first' available frame on either side)");
+                       uiBlockEndAlign(block);
+                       
+                       /* options */
+                       but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer");
+                       uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl);
+                       
+                       but= uiDefBut(block, BUT, B_REDR, "Del Last Stroke", *xco+160, *yco-95, 140, 20, NULL, 0, 0, 0, 0, "Erases the last stroke from the active frame");
+                       uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl);
+                       
+                       //uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco+160, *yco-75, 130, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
+               }
+       }
+       
+       /* adjust height for new to start */
+       (*yco) -= (height + 27); 
+} 
+
+/* Draw the contents for a grease-pencil panel. This assumes several things:
+ *     - that panel has been created, is 318 x 204. max yco is 225
+ *     - that a toggle for turning on/off gpencil drawing is 150 x 20, starting from (10,225)
+ * It will return the amount of extra space to extend the panel by
+ */
+short draw_gpencil_panel (uiBlock *block, bGPdata *gpd, ScrArea *sa)
+{
+       uiBut *but;
+       bGPDlayer *gpl;
+       short xco= 10, yco= 155;
+       
+       /* draw gpd settings first */
+       {
+               /* show status info button */
+               uiDefButBitI(block, TOG, GP_DATA_DISPINFO, B_REDR, "Show Status Info", 10, 205, 150, 20, &gpd->flag, 0, 0, 0, 0, "Display status info about current status of Grease Pencil");
+               
+               /* add new/duplicate layer buttons */
+               but= uiDefBut(block, BUT, B_REDR, "Add New Layer", 10,182,150,20, 0, 0, 0, 0, 0, "Adds a new Grease Pencil Layer");
+               uiButSetFunc(but, gp_ui_addlayer_cb, gpd, NULL);
+               
+               
+               /* show override lmb-clicks button */
+               uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 150, 20, &gpd->flag, 0, 0, 0, 0, "Interpret LMB-click as new strokes (same as holding Shift-Key per stroke)");
+               
+               /* 'view align' button (naming depends on context) */
+               if (sa->spacetype == SPACE_VIEW3D)
+                       uiDefButBitI(block, TOG, GP_DATA_VIEWALIGN, B_REDR, "Draw in 3D", 170, 205, 150, 20, &gpd->flag, 0, 0, 0, 0, "New strokes are added in 3D-space");
+               else if (sa->spacetype != SPACE_SEQ) /* not available for sequencer yet */
+                       uiDefButBitI(block, TOG, GP_DATA_VIEWALIGN, B_REDR, "Stick to View", 170, 205, 150, 20, &gpd->flag, 0, 0, 0, 0, "New strokes are added on 2d-canvas");
+               
+               /* show edit-in-action button */
+               but= uiDefButBitI(block, TOG, GP_DATA_EDITTIME, B_REDR, "Edit Timing", 170, 182, 150, 20, &gpd->flag, 0, 0, 0, 0, "Edit timing of frames for the Grease Pencil block");
+               uiButSetFunc(but, gp_ui_dotime_cb, gpd, NULL);
+       }
+       
+       /* draw for each layer */
+       for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+               gp_drawui_layer(block, gpd, gpl, &xco, &yco);
+       }
+       
+       /* return new height if necessary */
+       return (yco < 0) ? (204 - yco) : 204;
+}      
+
+/* ************************************************** */
+/* GREASE PENCIL DRAWING */
+
+/* flags for sflag */
+enum {
+       GP_DRAWDATA_NOSTATUS    = (1<<0),       /* don't draw status info */
+       GP_DRAWDATA_ONLY3D              = (1<<1),       /* only draw 3d-strokes */
+       GP_DRAWDATA_ONLYV2D             = (1<<2),       /* only draw 'canvas' strokes */
+};
+
+/* draw a given stroke */
+static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy)
+{
+       bGPDspoint *pt;
+       int i;
+       
+       /* error checking */
+       if ((points == NULL) || (totpoints <= 0))
+               return;
+       
+       /* check if stroke can be drawn */
+       if ((dflag & GP_DRAWDATA_ONLY3D) && !(sflag & GP_STROKE_3DSPACE))
+               return;
+       if (!(dflag & GP_DRAWDATA_ONLY3D) && (sflag & GP_STROKE_3DSPACE))
+               return;
+       if ((dflag & GP_DRAWDATA_ONLYV2D) && !(sflag & GP_STROKE_2DSPACE))
+               return;
+       if (!(dflag & GP_DRAWDATA_ONLYV2D) && (sflag & GP_STROKE_2DSPACE))
+               return;
+       
+       /* if drawing a single point, draw it larger */
+       if (totpoints == 1) {           
+               /* draw point */
+               if (sflag & GP_STROKE_3DSPACE) {
+                       glBegin(GL_POINTS);
+                               glVertex3f(points->x, points->y, points->z);
+                       glEnd();
+               }
+               else if (sflag & GP_STROKE_2DSPACE) {
+                       glBegin(GL_POINTS);
+                               glVertex2f(points->x, points->y);
+                       glEnd();
+               }
+               else {
+                       const float x= (points->x / 1000 * winx);
+                       const float y= (points->y / 1000 * winy);
+                       
+                       glBegin(GL_POINTS);
+                               glVertex2f(x, y);
+                       glEnd();
+               }
+       }
+       else {
+               float oldpressure = 0.0f;
+               
+               /* draw stroke curve */
+               glBegin(GL_LINE_STRIP);
+               for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
+                       float x, y, z;
+                       
+                       if (sflag & GP_STROKE_3DSPACE) {
+                               x= pt->x;
+                               y= pt->y;
+                               z= pt->z;
+                       }
+                       else if (sflag & GP_STROKE_2DSPACE) {
+                               x= pt->x;
+                               y= pt->y;
+                               z= 0;
+                       }
+                       else {
+                               x= (pt->x / 1000 * winx);
+                               y= (pt->y / 1000 * winy);
+                               z= 0;
+                       }
+                       
+                       if (fabs(pt->pressure - oldpressure) > 0.2f) {
+                               glEnd();
+                               glLineWidth(pt->pressure * thickness);
+                               glBegin(GL_LINE_STRIP);
+                               
+                               if (sflag & GP_STROKE_3DSPACE) 
+                                       glVertex3f(x, y, z);
+                               else
+                                       glVertex2f(x, y);
+                               
+                               oldpressure = pt->pressure;
+                       }
+                       else {
+                               if (sflag & GP_STROKE_3DSPACE) 
+                                       glVertex3f(x, y, z);
+                               else
+                                       glVertex2f(x, y);
+                       }
+               }
+               glEnd();
+               
+               /* draw debug points of curve on top? */
+               if (debug) {
+                       glBegin(GL_POINTS);
+                       for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
+                               if (sflag & GP_STROKE_3DSPACE) {
+                                       glVertex3f(pt->x, pt->y, pt->z);
+                               }
+                               else if (sflag & GP_STROKE_2DSPACE) {
+                                       glVertex2f(pt->x, pt->y);
+                               }
+                               else {
+                                       const float x= (pt->x / 1000 * winx);
+                                       const float y= (pt->y / 1000 * winy);
+                                       
+                                       glVertex2f(x, y);
+                               }
+                       }
+                       glEnd();
+               }
+       }
+}
+
+/* draw grease-pencil datablock */
+static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag)
+{
+       bGPDlayer *gpl, *actlay=NULL;
+       
+       /* turn on smooth lines (i.e. anti-aliasing) */
+       glEnable(GL_LINE_SMOOTH);
+       
+       /* turn on alpha-blending */
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glEnable(GL_BLEND);
+               
+       /* loop over layers, drawing them */
+       for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+               bGPDframe *gpf;
+               bGPDstroke *gps;
+               
+               short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
+               short lthick= gpl->thickness;
+               float color[4];
+               
+               /* don't draw layer if hidden */
+               if (gpl->flag & GP_LAYER_HIDE) 
+                       continue;
+               
+               /* if layer is active one, store pointer to it */
+               if (gpl->flag & GP_LAYER_ACTIVE)
+                       actlay= gpl;
+               
+               /* get frame to draw */
+               gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+               if (gpf == NULL) 
+                       continue;
+               
+               /* set color, stroke thickness, and point size */
+               glLineWidth(lthick);
+               QUATCOPY(color, gpl->color); // just for copying 4 array elements
+               glColor4f(color[0], color[1], color[2], color[3]);
+               glPointSize(gpl->thickness + 2);
+               
+               /* draw 'onionskins' (frame left + right) */
+               if (gpl->flag & GP_LAYER_ONIONSKIN) {
+                       /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/                      
+                       if (gpl->gstep) {
+                               bGPDframe *gf;
+                               short i;
+                               
+                               /* draw previous frames first */
+                               for (gf=gpf->prev, i=0; gf; gf=gf->prev, i++) {
+                                       /* check if frame is drawable */
+                                       if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
+                                               /* alpha decreases with distance from curframe index */
+                                               glColor4f(color[0], color[1], color[2], (color[3]-(i*0.7)));
+                                               
+                                               for (gps= gf->strokes.first; gps; gps= gps->next) {     
+                                                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+                                               }
+                                       }
+                                       else 
+                                               break;
+                               }
+                               
+                               /* now draw next frames */
+                               for (gf= gpf->next, i=0; gf; gf=gf->next, i++) {
+                                       /* check if frame is drawable */
+                                       if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
+                                               /* alpha decreases with distance from curframe index */
+                                               glColor4f(color[0], color[1], color[2], (color[3]-(i*0.7)));
+                                               
+                                               for (gps= gf->strokes.first; gps; gps= gps->next) {                                                             
+                                                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+                                               }
+                                       }
+                                       else 
+                                               break;
+                               }       
+                               
+                               /* restore alpha */
+                               glColor4f(color[0], color[1], color[2], color[3]);
+                       }
+                       else {
+                               /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+                               glColor4f(color[0], color[1], color[2], (color[3] / 7));
+                               
+                               if (gpf->prev) {
+                                       for (gps= gpf->prev->strokes.first; gps; gps= gps->next) {
+                                               gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+                                       }
+                               }
+                               
+                               glColor4f(color[0], color[1], color[2], (color[3] / 4));
+                               if (gpf->next) {
+                                       for (gps= gpf->next->strokes.first; gps; gps= gps->next) {      
+                                               gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+                                       }
+                               }
+                               
+                               /* restore alpha */
+                               glColor4f(color[0], color[1], color[2], color[3]);
+                       }
+               }
+               
+               /* draw the strokes already in active frame */
+               for (gps= gpf->strokes.first; gps; gps= gps->next) {    
+                       gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+               }
+               
+               /* Check if may need to draw the active stroke cache, only if this layer is the active layer
+                * that is being edited. (Stroke cache is currently stored in gp-data)
+                */
+               if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) &&
+                       (gpf->flag & GP_FRAME_PAINT)) 
+               {
+                       /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
+                       setlinestyle(2);
+                       gp_draw_stroke(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, debug, winx, winy);
+                       setlinestyle(0);
+               }
+       }
+       
+       /* turn off alpha blending, then smooth lines */
+       glDisable(GL_BLEND); // alpha blending
+       glDisable(GL_LINE_SMOOTH); // smooth lines
+       
+       /* show info for debugging the status of gpencil */
+       if ( ((dflag & GP_DRAWDATA_NOSTATUS)==0) && (gpd->flag & GP_DATA_DISPINFO) ) {
+               char printable[256];
+               short xmax;
+               
+               /* get text to display */
+               if (actlay) {
+                       if (gpd->flag & GP_DATA_EDITPAINT)
+                               BIF_ThemeColor(TH_BONE_POSE); // should be blue-ish
+                       else if (actlay->actframe == NULL)
+                               BIF_ThemeColor(TH_REDALERT);
+                       else if (actlay->actframe->framenum == CFRA)
+                               BIF_ThemeColor(TH_VERTEX_SELECT); // should be yellow
+                       else
+                               BIF_ThemeColor(TH_TEXT_HI);
+                       
+                       if (actlay->actframe) {
+                               sprintf(printable, "GPencil: Layer ('%s'), Frame (%d) %s", 
+                                       actlay->info, actlay->actframe->framenum,
+                                       ((gpd->flag & GP_DATA_EDITPAINT)?", Draw Mode On":"") );
+                       }
+                       else {
+                               sprintf(printable, "GPencil: Layer ('%s'), Frame <None> %s", 
+                                       actlay->info, ((gpd->flag & GP_DATA_EDITPAINT)?", Draw Mode On":"") );
+                       }
+               }
+               else {
+                       BIF_ThemeColor(TH_REDALERT);
+                       sprintf(printable, "GPencil: Layer <None>");
+               }
+               xmax= GetButStringLength(printable);
+               
+               /* only draw it if view is wide enough (assume padding of 20 is enough for now) */
+               if (winx > (xmax + 20)) { 
+                       glRasterPos2i(winx-xmax, winy-20);
+                       BMF_DrawString(G.fonts, printable);
+               }
+       }
+       
+       /* restore initial gl conditions */
+       glLineWidth(1.0);
+       glPointSize(1.0);
+       glColor4f(0, 0, 0, 1);
+}
+
+/* ----------- */
+
+/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 
+ * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes
+ */
+void draw_gpencil_2dview (ScrArea *sa, short onlyv2d)
+{
+       bGPdata *gpd;
+       int dflag = 0;
+       
+       /* check that we have grease-pencil stuff to draw */
+       if (sa == NULL) return;
+       gpd= gpencil_data_getactive(sa);
+       if (gpd == NULL) return;
+       
+       /* draw it! */
+       if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_NOSTATUS);
+       gp_draw_data(gpd, sa->winx, sa->winy, dflag);
+}
+
+/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 
+ * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, second time with only3d=0 for screen-aligned strokes
+ */
+void draw_gpencil_3dview (ScrArea *sa, short only3d)
+{
+       bGPdata *gpd;
+       int dflag = 0;
+       
+       /* check that we have grease-pencil stuff to draw */
+       gpd= gpencil_data_getactive(sa);
+       if (gpd == NULL) return;
+       
+       /* draw it! */
+       if (only3d) dflag |= (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_NOSTATUS);
+       gp_draw_data(gpd, sa->winx, sa->winy, dflag);
+}
+
+/* draw grease-pencil sketches to opengl render window assuming that matrices are already set correctly */
+void draw_gpencil_oglrender (View3D *v3d, int winx, int winy)
+{
+       bGPdata *gpd;
+       
+       /* assume gpencil data comes from v3d */
+       if (v3d == NULL) return;
+       gpd= v3d->gpd;
+       if (gpd == NULL) return;
+       
+       /* pass 1: draw 3d-strokes ------------ > */
+       gp_draw_data(gpd, winx, winy, (GP_DRAWDATA_NOSTATUS|GP_DRAWDATA_ONLY3D));
+       
+       /* pass 2: draw 2d-strokes ------------ > */
+               /* adjust view matrices */
+       myortho2(-0.375, (float)(winx)-0.375, -0.375, (float)(winy)-0.375);
+       glLoadIdentity();
+       
+               /* draw it! */
+       gp_draw_data(gpd, winx, winy, GP_DRAWDATA_NOSTATUS);
+}
+
+/* ************************************************** */
index 1169062fdd05da18e27a2018abf03f2233fec91e..3a73ee84ead109793e78bfe1de1102a82c8a327f 100644 (file)
@@ -37,6 +37,7 @@
 #include "DNA_action_types.h"
 #include "DNA_color_types.h"
 #include "DNA_customdata_types.h"
+#include "DNA_gpencil_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_ID.h"
 #include "DNA_image_types.h"
 #include "CMP_node.h"
 #include "SHD_node.h"
 
+#include "BDR_gpencil.h"
+
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
+#include "BIF_drawgpencil.h"
 #include "BIF_interface.h"
 #include "BIF_interface_icons.h"
 #include "BIF_language.h"
@@ -3300,6 +3304,66 @@ static void node_draw_group(ScrArea *sa, SpaceNode *snode, bNode *gnode)
 }
 
 
+
+static void nodes_panel_gpencil(short cntrl)   // NODES_HANDLER_GREASEPENCIL
+{
+       uiBlock *block;
+       SpaceNode *snode;
+       
+       snode= curarea->spacedata.first;
+
+       block= uiNewBlock(&curarea->uiblocks, "nodes_panel_gpencil", UI_EMBOSS, UI_HELV, curarea->win);
+       uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE  | cntrl);
+       uiSetPanelHandler(NODES_HANDLER_GREASEPENCIL);  // for close and esc
+       if (uiNewPanel(curarea, block, "Grease Pencil", "SpaceNode", 100, 30, 318, 204)==0) return;
+       
+       /* we can only really draw stuff if there are nodes (otherwise no events are handled */
+       if (snode->nodetree == NULL)
+               return;
+       
+       /* allocate memory for gpd if drawing enabled (this must be done first or else we crash) */
+       if (snode->flag & SNODE_DISPGP) {
+               if (snode->gpd == NULL)
+                       gpencil_data_setactive(curarea, gpencil_data_addnew());
+       }
+       
+       if (snode->flag & SNODE_DISPGP) {
+               bGPdata *gpd= snode->gpd;
+               short newheight;
+               
+               /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+               /* so first we make it default height */
+               uiNewPanelHeight(block, 204);
+               
+               /* draw button for showing gpencil settings and drawings */
+               uiDefButBitS(block, TOG, SNODE_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &snode->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Node Editor");
+               
+               /* extend the panel if the contents won't fit */
+               newheight= draw_gpencil_panel(block, gpd, curarea); 
+               uiNewPanelHeight(block, newheight);
+       }
+       else {
+               uiDefButBitS(block, TOG, SNODE_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &snode->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Node Editor");
+               uiDefBut(block, LABEL, 1, " ",  160, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
+       }
+}
+
+static void nodes_blockhandlers(ScrArea *sa)
+{
+       SpaceNode *snode= sa->spacedata.first;
+       short a;
+       
+       for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+               /* clear action value for event */
+               switch(snode->blockhandler[a]) {
+                       case NODES_HANDLER_GREASEPENCIL:
+                               nodes_panel_gpencil(snode->blockhandler[a+1]);
+                               break;
+               }
+       }
+       uiDrawBlocksPanels(sa, 0);
+}
+
 void drawnodespace(ScrArea *sa, void *spacedata)
 {
        SpaceNode *snode= sa->spacedata.first;
@@ -3354,13 +3418,26 @@ void drawnodespace(ScrArea *sa, void *spacedata)
                }
        }
        
+       /* draw grease-pencil ('canvas' strokes) */
+       if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
+               draw_gpencil_2dview(sa, 1);
+       
        /* restore viewport (not needed yet) */
        mywinset(sa->win);
 
        /* ortho at pixel level curarea */
        myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+       
+       /* draw grease-pencil (screen strokes) */
+       if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
+               draw_gpencil_2dview(sa, 0);
 
        draw_area_emboss(sa);
+       
+       /* it is important to end a view in a transform compatible with buttons */
+       bwin_scalematrix(sa->win, snode->blockscale, snode->blockscale, snode->blockscale);
+       nodes_blockhandlers(sa);
+       
        curarea->win_swap= WIN_BACK_OK;
        
        /* in the end, this is a delayed previewrender test, to allow buttons to be first */
index e554b91dd52a03bb400bdb845ebf57b3c16313b0..c8c74ad827940cebf1762dbc01d9bbd9f7f048bb 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "IMB_imbuf_types.h"
 
+#include "DNA_gpencil_types.h"
 #include "DNA_sequence_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
@@ -67,6 +68,9 @@
 #include "BIF_space.h"
 #include "BIF_interface.h"
 
+#include "BIF_drawgpencil.h"
+#include "BDR_gpencil.h"
+
 #include "BSE_view.h"
 #include "BSE_drawipo.h"
 #include "BSE_sequence.h"
@@ -98,6 +102,70 @@ static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2)
 static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2);
 static void draw_seq_strip(struct Sequence *seq, struct ScrArea *sa, struct SpaceSeq *sseq, int outline_tint, float pixelx);
 
+
+static void seq_panel_gpencil(short cntrl)     // SEQ_HANDLER_GREASEPENCIL
+{
+       uiBlock *block;
+       SpaceSeq *sseq;
+       
+       sseq= curarea->spacedata.first;
+
+       block= uiNewBlock(&curarea->uiblocks, "seq_panel_gpencil", UI_EMBOSS, UI_HELV, curarea->win);
+       uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE  | cntrl);
+       uiSetPanelHandler(SEQ_HANDLER_GREASEPENCIL);  // for close and esc
+       if (uiNewPanel(curarea, block, "Grease Pencil", "SpaceSeq", 100, 30, 318, 204)==0) return;
+       
+       /* only draw settings if right mode */
+       if (sseq->mainb == 0)
+               return;
+       
+       /* allocate memory for gpd if drawing enabled (this must be done first or else we crash) */
+       if (sseq->flag & SEQ_DRAW_GPENCIL) {
+               if (sseq->gpd == NULL)
+                       gpencil_data_setactive(curarea, gpencil_data_addnew());
+       }
+       
+       if (sseq->flag & SEQ_DRAW_GPENCIL) {
+               bGPdata *gpd= sseq->gpd;
+               short newheight;
+               
+               /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+               /* so first we make it default height */
+               uiNewPanelHeight(block, 204);
+               
+               /* draw button for showing gpencil settings and drawings */
+               uiDefButBitI(block, TOG, SEQ_DRAW_GPENCIL, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &sseq->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Sequencer View");
+               
+               /* extend the panel if the contents won't fit */
+               newheight= draw_gpencil_panel(block, gpd, curarea); 
+               uiNewPanelHeight(block, newheight);
+       }
+       else {
+               uiDefButBitI(block, TOG, SEQ_DRAW_GPENCIL, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &sseq->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Sequencer View");
+               uiDefBut(block, LABEL, 1, " ",  160, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
+       }
+}
+
+static void seq_blockhandlers(ScrArea *sa)
+{
+       SpaceSeq *sseq= sa->spacedata.first;
+       short a;
+
+       /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
+       uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+       for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+               switch(sseq->blockhandler[a]) {
+                       case SEQ_HANDLER_GREASEPENCIL:
+                               seq_panel_gpencil(sseq->blockhandler[a+1]);
+                               break;
+               }
+       }
+       uiDrawBlocksPanels(sa, 0);
+
+}
+
+
 static void draw_cfra_seq(void)
 {
        glColor3ub(0x30, 0x90, 0x50);
@@ -907,6 +975,17 @@ static void draw_image_seq(ScrArea *sa)
        if (free_ibuf) {
                IMB_freeImBuf(ibuf);
        } 
+       
+       /* draw grease-pencil (screen aligned) */
+       if (sseq->flag & SEQ_DRAW_GPENCIL)
+               draw_gpencil_2dview(sa, 0);
+       
+       /* ortho at pixel level sa */
+       myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+       
+       /* it is important to end a view in a transform compatible with buttons */
+       bwin_scalematrix(sa->win, sseq->blockscale, sseq->blockscale, sseq->blockscale);
+       seq_blockhandlers(sa);
 
        sa->win_swap= WIN_BACK_OK;
 }
@@ -1023,24 +1102,6 @@ void seq_viewmove(SpaceSeq *sseq)
        window_set_cursor(win, oldcursor);
 }
 
-
-
-static void seq_blockhandlers(ScrArea *sa)
-{
-       SpaceSeq *sseq= sa->spacedata.first;
-       short a;
-
-       /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
-       uiFreeBlocksWin(&sa->uiblocks, sa->win);
-
-       for(a=0; a<SPACE_MAXHANDLER; a+=2) {
-               /* clear action value for event */
-               sseq->blockhandler[a+1]= 0;
-       }
-       uiDrawBlocksPanels(sa, 0);
-
-}
-
 void drawprefetchseqspace(ScrArea *sa, void *spacedata)
 {
        SpaceSeq *sseq= sa->spacedata.first;
index f595a101f63e3484a069430faa44f09bf2de62f8..14434504e7aa8338fc0b1682ea2b38f31d3db327 100644 (file)
@@ -61,6 +61,7 @@
 #include "DNA_constraint_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
 #include "DNA_image_types.h"
 #include "DNA_key_types.h"
 #include "DNA_lattice_types.h"
 
 #include "BIF_butspace.h"
 #include "BIF_drawimage.h"
+#include "BIF_drawgpencil.h"
 #include "BIF_editgroup.h"
 #include "BIF_editarmature.h"
 #include "BIF_editmesh.h"
 #include "BDR_editobject.h"
 #include "BDR_vpaint.h"
 #include "BDR_sculptmode.h"
+#include "BDR_gpencil.h"
 
 #include "BSE_drawview.h"
 #include "BSE_filesel.h"
@@ -2498,7 +2501,7 @@ static void view3d_panel_background(short cntrl)  // VIEW3D_HANDLER_BACKGROUND
        uiSetPanelHandler(VIEW3D_HANDLER_BACKGROUND);  // for close and esc
        if(uiNewPanel(curarea, block, "Background Image", "View3d", 340, 10, 318, 204)==0) return;
 
-       if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT || G.f & G_TEXTUREPAINT) {
+       if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT || G.f & G_TEXTUREPAINT || G.f & G_GREASEPENCIL) {
                uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER);    // force old style frontbuffer draw
        }
        
@@ -2546,7 +2549,7 @@ static void view3d_panel_properties(short cntrl)  // VIEW3D_HANDLER_SETTINGS
        /* to force height */
        uiNewPanelHeight(block, 264);
 
-       if(G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT)) {
+       if(G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT|G_GREASEPENCIL)) {
                uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER);    // force old style frontbuffer draw
        }
 
@@ -2620,6 +2623,49 @@ static void view3d_panel_preview(ScrArea *sa, short cntrl)       // VIEW3D_HANDLER_PRE
        }
 }
 
+static void view3d_panel_gpencil(short cntrl)  // VIEW3D_HANDLER_GREASEPENCIL
+{
+       uiBlock *block;
+       View3D *vd;
+       
+       vd= G.vd;
+
+       block= uiNewBlock(&curarea->uiblocks, "view3d_panel_gpencil", UI_EMBOSS, UI_HELV, curarea->win);
+       uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE  | cntrl);
+       uiSetPanelHandler(VIEW3D_HANDLER_GREASEPENCIL);  // for close and esc
+       if (uiNewPanel(curarea, block, "Grease Pencil", "View3d", 100, 30, 318, 204)==0) return;
+
+       if (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT|G_GREASEPENCIL)) {
+               uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER);    // force old style frontbuffer draw
+       }
+       
+       /* allocate memory for gpd if drawing enabled (this must be done first or else we crash) */
+       if (vd->flag2 & V3D_DISPGP) {
+               if (vd->gpd == NULL)
+                       gpencil_data_setactive(curarea, gpencil_data_addnew());
+       }
+       
+       if (vd->flag2 & V3D_DISPGP) {
+               bGPdata *gpd= vd->gpd;
+               short newheight;
+               
+               /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+               /* so first we make it default height */
+               uiNewPanelHeight(block, 204);
+               
+               /* draw button for showing gpencil settings and drawings */
+               uiDefButBitS(block, TOG, V3D_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &vd->flag2, 0, 0, 0, 0, "Display freehand annotations overlay over this 3D View");
+               
+               /* extend the panel if the contents won't fit */
+               newheight= draw_gpencil_panel(block, gpd, curarea); 
+               uiNewPanelHeight(block, newheight);
+       }
+       else {
+               uiDefButBitS(block, TOG, V3D_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &vd->flag2, 0, 0, 0, 0, "Display freehand annotations overlay over this 3D View");
+               uiDefBut(block, LABEL, 1, " ",  160, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
+       }
+}
+
 
 static void view3d_blockhandlers(ScrArea *sa)
 {
@@ -2634,9 +2680,7 @@ static void view3d_blockhandlers(ScrArea *sa)
        glDisable(GL_DEPTH_TEST); 
        
        for(a=0; a<SPACE_MAXHANDLER; a+=2) {
-       
                switch(v3d->blockhandler[a]) {
-
                case VIEW3D_HANDLER_PROPERTIES:
                        view3d_panel_properties(v3d->blockhandler[a+1]);
                        break;
@@ -2651,7 +2695,10 @@ static void view3d_blockhandlers(ScrArea *sa)
                        break;                  
                case VIEW3D_HANDLER_TRANSFORM:
                        view3d_panel_transform_spaces(v3d->blockhandler[a+1]);
-                       break;                  
+                       break;
+               case VIEW3D_HANDLER_GREASEPENCIL:
+                       view3d_panel_gpencil(v3d->blockhandler[a+1]);
+                       break;
                }
                /* clear action value for event */
                v3d->blockhandler[a+1]= 0;
@@ -3169,7 +3216,11 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
                v3d->zbuf= FALSE;
                glDisable(GL_DEPTH_TEST);
        }
-
+       
+       /* draw grease-pencil stuff */
+       if (v3d->flag2 & V3D_DISPGP)
+               draw_gpencil_3dview(sa, 1);
+       
        persp(PERSP_WIN);  // set ortho
 
        /* Draw Sculpt Mode brush */
@@ -3211,6 +3262,11 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
 
        if(v3d->persp>1) drawviewborder();
        if(v3d->flag2 & V3D_FLYMODE) drawviewborder_flymode();
+       
+       /* draw grease-pencil stuff */
+       if (v3d->flag2 & V3D_DISPGP)
+               draw_gpencil_3dview(sa, 0);
+       
        if(!(G.f & G_PLAYANIM)) drawcursor(v3d);
        if(U.uiflag & USER_SHOW_ROTVIEWICON)
                draw_view_axis();
@@ -3311,16 +3367,15 @@ void drawview3d_render(struct View3D *v3d, int winx, int winy, float winmat[][4]
 
        /* first draw set */
        if(G.scene->set) {
-       
                for(SETLOOPER(G.scene->set, base)) {
                        if(v3d->lay & base->lay) {
                                if ELEM3(base->object->type, OB_LAMP, OB_CAMERA, OB_LATTICE);
                                else {
                                        where_is_object(base->object);
-       
+                                       
                                        BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
                                        draw_object(base, DRAW_CONSTCOLOR|DRAW_SCENESET);
-       
+                                       
                                        if(base->object->transflag & OB_DUPLI) {
                                                draw_dupli_objects(v3d, base);
                                        }
@@ -3377,6 +3432,13 @@ void drawview3d_render(struct View3D *v3d, int winx, int winy, float winmat[][4]
                glDisable(GL_DEPTH_TEST);
        }
        
+       if(v3d->gpd) {
+               /* draw grease-pencil overlays 
+                * WARNING: view matrices are altered here!
+                */
+               draw_gpencil_oglrender(v3d, winx, winy);
+       }
+       
        G.f &= ~G_SIMULATION;
 
        glFlush();
index 4cc0e52ce3f757a85ba8a39ac921310bf66c8157..3251cb33b53766716d15bcc9fc69108fd8670664 100644 (file)
@@ -52,6 +52,7 @@
 #include "DNA_mesh_types.h"
 #include "DNA_nla_types.h"
 #include "DNA_lattice_types.h"
+#include "DNA_gpencil_types.h"
 
 #include "BKE_action.h"
 #include "BKE_armature.h"
@@ -90,6 +91,7 @@
 
 #include "BDR_drawaction.h"
 #include "BDR_editobject.h"
+#include "BDR_gpencil.h"
 
 #include "mydevice.h"
 #include "blendef.h"
@@ -296,6 +298,16 @@ bActListElem *make_new_actlistelem (void *data, short datatype, void *owner, sho
                                ale->datatype= ALE_IPO;
                        }
                                break;
+                       case ACTTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl= (bGPDlayer *)data;
+                               
+                               ale->flag= gpl->flag;
+                               
+                               ale->key_data= NULL;
+                               ale->datatype= ALE_GPFRAME;
+                       }
+                               break;
                }
        }
        
@@ -505,6 +517,29 @@ static void actdata_filter_shapekey (ListBase *act_data, Key *key, int filter_mo
        }
 }
  
+static void actdata_filter_gpencil (ListBase *act_data, bGPdata *gpd, int filter_mode)
+{
+       bActListElem *ale;
+       bGPDlayer *gpl;
+       
+       /* check if filtering types are appropriate */
+       if ( !(filter_mode & (ACTFILTER_IPOKEYS|ACTFILTER_ONLYICU|ACTFILTER_ACTGROUPED)) ) 
+       {
+               /* loop over layers as the conditions are acceptable */
+               for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+                       /* only if selected */
+                       if (!(filter_mode & ACTFILTER_SEL) || SEL_GPL(gpl)) {
+                               /* only if editable */
+                               if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
+                                       /* add to list */
+                                       ale= make_new_actlistelem(gpl, ACTTYPE_GPLAYER, NULL, ACTTYPE_NONE);
+                                       if (ale) BLI_addtail(act_data, ale);
+                               }
+                       }
+               }
+       }
+}
 /* This function filters the active data source to leave only the desired
  * data types. 'Public' api call.
  *     *act_data: is a pointer to a ListBase, to which the filtered action data 
@@ -525,6 +560,9 @@ void actdata_filter (ListBase *act_data, int filter_mode, void *data, short data
                        case ACTCONT_SHAPEKEY:
                                actdata_filter_shapekey(act_data, data, filter_mode);
                                break;
+                       case ACTCONT_GPENCIL:
+                               actdata_filter_gpencil(act_data, data, filter_mode);
+                               break;
                }
                        
                /* remove any weedy entries */
@@ -743,6 +781,10 @@ static void *get_nearest_action_key (float *selx, short *sel, short *ret_type, b
                                bActionGroup *agrp= (bActionGroup *)ale->data;
                                agroup_to_keylist(agrp, &act_keys, NULL, NULL);
                        }
+                       else if (ale->type == ACTTYPE_GPLAYER) {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               gpl_to_keylist(gpl, &act_keys, NULL, NULL);
+                       }
                        
                        /* loop through keyframes, finding one that was clicked on */
                        for (ak= act_keys.first; ak; ak= ak->next) {
@@ -766,6 +808,10 @@ static void *get_nearest_action_key (float *selx, short *sel, short *ret_type, b
                                data = ale->key_data;
                                *ret_type= ACTTYPE_ICU;
                        }
+                       else if (datatype == ACTCONT_GPENCIL) {
+                               data = ale->data;
+                               *ret_type= ACTTYPE_GPLAYER;
+                       }
                        
                        /* cleanup tempolary lists */
                        BLI_freelistN(&act_keys);
@@ -795,17 +841,43 @@ void *get_action_context (short *datatype)
        act = (G.saction)? G.saction->action: NULL;
        key = get_action_mesh_key();
        
-       if (act) {
-               *datatype= ACTCONT_ACTION;
-               return act;
-       }
-       else if (key) {
-               *datatype= ACTCONT_SHAPEKEY;
-               return key;
+       /* check mode selector */
+       if (G.saction) {
+               switch (G.saction->mode) {
+                       case SACTCONT_ACTION: 
+                               *datatype= ACTCONT_ACTION;
+                               return act;
+                               
+                       case SACTCONT_SHAPEKEY:
+                               *datatype= ACTCONT_SHAPEKEY;
+                               return key;
+                               
+                       case SACTCONT_GPENCIL:
+                               *datatype= ACTCONT_GPENCIL;
+                               if (G.saction->pin)
+                                       return G.saction->gpd;
+                               else
+                                       return gpencil_data_getetime(G.curscreen);
+                       
+                       default: /* includes SACTCONT_DOPESHEET for now */
+                               *datatype= ACTCONT_NONE;
+                               return NULL;
+               }
        }
        else {
-               *datatype= ACTCONT_NONE;
-               return NULL;
+               /* resort to guessing based on what is available */
+               if (act) {
+                       *datatype= ACTCONT_ACTION;
+                       return act;
+               }
+               else if (key) {
+                       *datatype= ACTCONT_SHAPEKEY;
+                       return key;
+               }
+               else {
+                       *datatype= ACTCONT_NONE;
+                       return NULL;
+               }
        }
 }
 
@@ -1307,12 +1379,18 @@ void duplicate_action_keys (void)
        if (data == NULL) return;
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* loop through filtered data and duplicate selected keys */
        for (ale= act_data.first; ale; ale= ale->next) {
-               duplicate_ipo_keys((Ipo *)ale->key_data);
+               if (ale->type == ACTTYPE_GPLAYER)
+                       duplicate_gplayer_frames(ale->data);
+               else
+                       duplicate_ipo_keys((Ipo *)ale->key_data);
        }
        
        /* free filtered list */
@@ -1398,7 +1476,10 @@ void snap_action_keys(short mode)
        }
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* snap to frame */
@@ -1408,6 +1489,8 @@ void snap_action_keys(short mode)
                        snap_ipo_keys(ale->key_data, mode);
                        actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
                }
+               else if (ale->type == ACTTYPE_GPLAYER)
+                       snap_gplayer_frames(ale->data, mode);
                else 
                        snap_ipo_keys(ale->key_data, mode);
        }
@@ -1421,6 +1504,7 @@ void snap_action_keys(short mode)
        allqueue(REDRAWACTION, 0);
        allqueue(REDRAWIPO, 0);
        allqueue(REDRAWNLA, 0);
+       allqueue(REDRAWVIEW3D, 0);
 }
 
 /* this function is responsible for snapping keyframes to frame-times */
@@ -1456,7 +1540,10 @@ void mirror_action_keys(short mode)
        }
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* mirror */
@@ -1466,6 +1553,8 @@ void mirror_action_keys(short mode)
                        mirror_ipo_keys(ale->key_data, mode);
                        actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
                }
+               else if (ale->type == ACTTYPE_GPLAYER)
+                       mirror_gplayer_frames(ale->data, mode);
                else 
                        mirror_ipo_keys(ale->key_data, mode);
        }
@@ -1550,6 +1639,10 @@ void insertkey_action(void)
                        }
                }
        }
+       else {
+               /* this tool is not supported in this mode */
+               return;
+       }
        
        BIF_undo_push("Insert Key");
        allspace(REMAKEIPO, 0);
@@ -1573,12 +1666,18 @@ void delete_action_keys (void)
        if (data == NULL) return;
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* loop through filtered data and delete selected keys */
        for (ale= act_data.first; ale; ale= ale->next) {
-               delete_ipo_keys((Ipo *)ale->key_data);
+               if (ale->type == ACTTYPE_GPLAYER)
+                       delete_gplayer_frames((bGPDlayer *)ale->data);
+               else
+                       delete_ipo_keys((Ipo *)ale->key_data);
        }
        
        /* free filtered list */
@@ -1699,6 +1798,7 @@ void clean_action (void)
                                0.0000001f, 1.0, 0.001, 0.1,
                                "Clean Threshold");
        if (!ok) return;
+       if (datatype == ACTCONT_GPENCIL) return;
        
        /* filter data */
        filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_SEL | ACTFILTER_ONLYICU);
@@ -1737,6 +1837,7 @@ void sample_action_keys (void)
        /* sanity checks */
        data= get_action_context(&datatype);
        if (data == NULL) return;
+       if (datatype == ACTCONT_GPENCIL) return;
        
        /* filter data */
        filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
@@ -2096,6 +2197,7 @@ void action_set_ipo_flags (short mode, short event)
        /* determine what type of data we are operating on */
        data = get_action_context(&datatype);
        if (data == NULL) return;
+       if (datatype == ACTCONT_GPENCIL) return;
        
        /* determine which set of processing we are doing */
        switch (mode) {
@@ -2194,6 +2296,7 @@ void sethandles_action_keys (int code)
        /* determine what type of data we are operating on */
        data = get_action_context(&datatype);
        if (data == NULL) return;
+       if (datatype == ACTCONT_GPENCIL) return;
        
        /* filter data */
        filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
@@ -2232,11 +2335,12 @@ static void numbuts_action ()
        bConstraintChannel *conchan= NULL;
        IpoCurve *icu= NULL;
        KeyBlock *kb= NULL;
+       bGPDlayer *gpl= NULL;
        
        short mval[2];
        
        int but=0;
-    char str[64];
+    char str[128];
        short expand, protect, mute;
        float slidermin, slidermax;
        
@@ -2345,6 +2449,18 @@ static void numbuts_action ()
                add_numbut(but++, TOG|SHO, "Expanded", 0, 24, &expand, "Action Group is Expanded");
                add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Group is Protected");
        }
+       else if (chantype == ACTTYPE_GPLAYER) {
+               /* Grease-Pencil Layer */
+               gpl= (bGPDlayer *)act_channel;
+               
+               strcpy(str, gpl->info);
+               protect= (gpl->flag & GP_LAYER_LOCKED);
+               mute = (gpl->flag & GP_LAYER_HIDE);
+               
+               add_numbut(but++, TEX, "GP-Layer: ", 0, 128, str, "Name of Grease Pencil Layer");
+               add_numbut(but++, TOG|SHO, "Hide", 0, 24, &mute, "Grease Pencil Layer is Visible");
+               add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Grease Pencil Layer is Protected");
+       }
        else {
                /* nothing under-cursor */
                return;
@@ -2393,6 +2509,16 @@ static void numbuts_action ()
                        if (protect) agrp->flag |= AGRP_PROTECTED;
                        else agrp->flag &= ~AGRP_PROTECTED;
                }
+               else if (gpl) {
+                       strcpy(gpl->info, str);
+                       BLI_uniquename(&( ((bGPdata *)data)->layers ), gpl, "GP_Layer", offsetof(bGPDlayer, info), 128);
+                       
+                       if (mute) gpl->flag |= GP_LAYER_HIDE;
+                       else gpl->flag &= ~GP_LAYER_HIDE;;
+                       
+                       if (protect) gpl->flag |= GP_LAYER_LOCKED;
+                       else gpl->flag &= ~GP_LAYER_LOCKED;
+               }
                
         allqueue(REDRAWACTION, 0);
                allspace(REMAKEIPO, 0);
@@ -2524,6 +2650,31 @@ void setflag_action_channels (short mode)
                                }
                        }
                                break;
+                       case ACTTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               
+                               /* 'protect' and 'mute' */
+                               if (val == 2) {
+                                       /* mute */
+                                       if (mode == 2)
+                                               gpl->flag &= ~GP_LAYER_HIDE;
+                                       else if (mode == 1)
+                                               gpl->flag |= GP_LAYER_HIDE;
+                                       else
+                                               gpl->flag ^= GP_LAYER_HIDE;
+                               }
+                               else if (val == 1) {
+                                       /* protected */
+                                       if (mode == 2)
+                                               gpl->flag &= ~GP_LAYER_LOCKED;
+                                       else if (mode == 1)
+                                               gpl->flag |= GP_LAYER_LOCKED;
+                                       else
+                                               gpl->flag ^= GP_LAYER_LOCKED;
+                               }
+                       }
+                               break;
                }
        }
        BLI_freelistN(&act_data);
@@ -2564,7 +2715,7 @@ static void select_action_group (bAction *act, bActionGroup *agrp, int selectmod
        set_active_actiongroup(act, agrp, select);
 }
 
-static void hilight_channel(bAction *act, bActionChannel *achan, short select)
+static void hilight_channel (bAction *act, bActionChannel *achan, short select)
 {
        bActionChannel *curchan;
 
@@ -2637,7 +2788,7 @@ void select_actionchannel_by_name (bAction *act, char *name, int select)
 
 /* exported for outliner (ton) */
 /* apparently within active object context */
-int select_channel(bAction *act, bActionChannel *achan, int selectmode) 
+int select_channel (bAction *act, bActionChannel *achan, int selectmode) 
 {
        /* Select the channel based on the selection mode */
        int flag;
@@ -2661,9 +2812,9 @@ int select_channel(bAction *act, bActionChannel *achan, int selectmode)
        return flag;
 }
 
-static int select_constraint_channel(bAction *act, 
-                                     bConstraintChannel *conchan, 
-                                     int selectmode) 
+static int select_constraint_channel (bAction *act, 
+                                      bConstraintChannel *conchan, 
+                                      int selectmode) 
 {
        /* Select the constraint channel based on the selection mode */
        int flag;
@@ -2684,7 +2835,7 @@ static int select_constraint_channel(bAction *act,
        return flag;
 }
 
-int select_icu_channel(bAction *act, IpoCurve *icu, int selectmode) 
+int select_icu_channel (bAction *act, IpoCurve *icu, int selectmode) 
 {
        /* Select the channel based on the selection mode */
        int flag;
@@ -2704,6 +2855,29 @@ int select_icu_channel(bAction *act, IpoCurve *icu, int selectmode)
        return flag;
 }
 
+int select_gplayer_channel (bGPdata *gpd, bGPDlayer *gpl, int selectmode) 
+{
+       /* Select the channel based on the selection mode */
+       int flag;
+
+       switch (selectmode) {
+       case SELECT_ADD:
+               gpl->flag |= GP_LAYER_SELECT;
+               break;
+       case SELECT_SUBTRACT:
+               gpl->flag &= ~GP_LAYER_SELECT;
+               break;
+       case SELECT_INVERT:
+               gpl->flag ^= GP_LAYER_SELECT;
+               break;
+       }
+       flag = (gpl->flag & GP_LAYER_SELECT) ? 1 : 0;
+
+       gpencil_layer_setactive(gpd, gpl);
+
+       return flag;
+}
+
 
 /* select only the active action-group's action channels */
 void select_action_group_channels (bAction *act, bActionGroup *agrp)
@@ -2848,6 +3022,8 @@ void deselect_action_channels (short mode)
        /* based on type */
        if (datatype == ACTCONT_ACTION)
                deselect_actionchannels(data, mode);
+       else if (datatype == ACTCONT_GPENCIL)
+               deselect_gpencil_layers(data, mode);
        // should shapekey channels be allowed to do this? 
 }
 
@@ -2863,24 +3039,40 @@ void deselect_action_keys (short test, short sel)
        /* determine what type of data we are operating on */
        data = get_action_context(&datatype);
        if (data == NULL) return;
-               
+       
+       /* determine type-based settings */
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+       
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* See if we should be selecting or deselecting */
        if (test) {
                for (ale= act_data.first; ale; ale= ale->next) {
-                       if (is_ipo_key_selected(ale->key_data)) {
-                               sel= 0;
-                               break;
+                       if (ale->type == ACTTYPE_GPLAYER) {
+                               if (is_gplayer_frame_selected(ale->data)) {
+                                       sel= 0;
+                                       break;
+                               }
+                       }
+                       else {
+                               if (is_ipo_key_selected(ale->key_data)) {
+                                       sel= 0;
+                                       break;
+                               }
                        }
                }
        }
                
        /* Now set the flags */
        for (ale= act_data.first; ale; ale= ale->next) {
-               set_ipo_key_selection(ale->key_data, sel);
+               if (ale->type == ACTTYPE_GPLAYER)
+                       set_gplayer_frame_selection(ale->data, sel);
+               else
+                       set_ipo_key_selection(ale->key_data, sel);
        }
        
        /* Cleanup */
@@ -2946,6 +3138,12 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
                                        select_icu_bezier_keys(icu, select_mode);
                                }
                                        break;
+                               case ACTTYPE_GPLAYER:
+                               {
+                                       bGPDlayer *gpl= (bGPDlayer *)act_channel;
+                                       select_gpencil_frames(gpl, select_mode);
+                               }
+                                       break;
                        }
                }
                        break;
@@ -2971,12 +3169,16 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
                        rectf.xmax = rectf.xmax + 0.5;
                        
                        /* filter data */
-                       filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+                       if (datatype == ACTCONT_GPENCIL)
+                               filter= (ACTFILTER_VISIBLE);
+                       else
+                               filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
                        actdata_filter(&act_data, filter, data, datatype);
                                
                        /* Now set the flags */
-                       for (ale= act_data.first; ale; ale= ale->next)
+                       for (ale= act_data.first; ale; ale= ale->next) {
                                borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, select_mode);
+                       }
                        
                        /* Cleanup */
                        BLI_freelistN(&act_data);
@@ -3058,19 +3260,23 @@ void selectkeys_leftright (short leftright, short select_mode)
        }
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
                
        /* select keys on the side where most data occurs */
        for (ale= act_data.first; ale; ale= ale->next) {
-               if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+               if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
                        actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
                        borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
                        actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
                }
-               else {
+               else if (ale->type == ACTTYPE_GPLAYER)
+                       borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
+               else
                        borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
-               }
        }
        
        /* Cleanup */
@@ -3108,7 +3314,10 @@ void nextprev_action_keyframe (short dir)
                return;
        
        /* get list of keyframes that can be used (in global-time) */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        for (ale= act_data.first; ale; ale= ale->next) {
@@ -3117,6 +3326,8 @@ void nextprev_action_keyframe (short dir)
                        make_cfra_list(ale->key_data, &elems);
                        actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
                }
+               else if (ale->type == ACTTYPE_GPLAYER)
+                       gplayer_make_cfra_list(ale->key_data, &elems, 0);
                else 
                        make_cfra_list(ale->key_data, &elems);
        }
@@ -3199,11 +3410,20 @@ void column_select_action_keys (int mode)
        /* build list of columns */
        switch (mode) {
                case 1: /* list of selected keys */
-                       filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
-                       actdata_filter(&act_data, filter, data, datatype);
-                       
-                       for (ale= act_data.first; ale; ale= ale->next)
-                               make_sel_cfra_list(ale->key_data, &elems);
+                       if (datatype == ACTCONT_GPENCIL) {
+                               filter= (ACTFILTER_VISIBLE);
+                               actdata_filter(&act_data, filter, data, datatype);
+                               
+                               for (ale= act_data.first; ale; ale= ale->next)
+                                       gplayer_make_cfra_list(ale->data, &elems, 1);
+                       }
+                       else {
+                               filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+                               actdata_filter(&act_data, filter, data, datatype);
+                               
+                               for (ale= act_data.first; ale; ale= ale->next)
+                                       make_sel_cfra_list(ale->key_data, &elems);
+                       }
                        
                        BLI_freelistN(&act_data);
                        break;
@@ -3231,19 +3451,34 @@ void column_select_action_keys (int mode)
        /* loop through all of the keys and select additional keyframes
         * based on the keys found to be selected above
         */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
        actdata_filter(&act_data, filter, data, datatype);
        
        for (ale= act_data.first; ale; ale= ale->next) {
                for (ce= elems.first; ce; ce= ce->next) {
-                       for (icu= ale->key_data; icu; icu= icu->next) {
-                               BezTriple *bezt;
-                               int verts = 0;
+                       /* select elements with frame number matching cfraelem */
+                       if (ale->type == ACTTYPE_GPLAYER) {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               bGPDframe *gpf;
                                
-                               for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
-                                       if (bezt) {
-                                               if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
-                                                       bezt->f2 |= 1;
+                               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                                       if ( (int)ce->cfra == gpf->framenum ) 
+                                               gpf->flag |= GP_FRAME_SELECT;
+                               }
+                       }
+                       else {
+                               for (icu= ale->key_data; icu; icu= icu->next) {
+                                       BezTriple *bezt;
+                                       int verts = 0;
+                                       
+                                       for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
+                                               if (bezt) {
+                                                       if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
+                                                               bezt->f2 |= 1;
+                                               }
                                        }
                                }
                        }
@@ -3272,7 +3507,7 @@ void borderselect_actionchannels (void)
        /* determine what type of data we are operating on */
        data = get_action_context(&datatype);
        if (data == NULL) return;
-       if (datatype != ACTCONT_ACTION) return;
+       if (ELEM(datatype, ACTCONT_ACTION, ACTCONT_GPENCIL)==0) return;
        
        /* draw and handle the borderselect stuff (ui) and get the select rect */
        if ( (val = get_border(&rect, 3)) ) {
@@ -3344,6 +3579,16 @@ void borderselect_actionchannels (void)
                                                        icu->flag &= ~IPO_SELECT;
                                        }
                                                break;
+                                       case ACTTYPE_GPLAYER: /* grease-pencil layer */
+                                       {
+                                               bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                                               
+                                               if (selectmode == SELECT_ADD)
+                                                       gpl->flag |= GP_LAYER_SELECT;
+                                               else
+                                                       gpl->flag &= ~GP_LAYER_SELECT;
+                                       }
+                                               break;
                                }
                                
                                /* select action-channel 'owner' */
@@ -3460,6 +3705,9 @@ void borderselect_action (void)
                                                        borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
                                        }
                                }
+                               else if (ale->type == ACTTYPE_GPLAYER) {
+                                       borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+                               }
                                break;
                        case ACTEDIT_BORDERSEL_CHA: /* all in channel(s) */
                                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -3481,6 +3729,9 @@ void borderselect_action (void)
                                                                select_ipo_bezier_keys(conchan->ipo, selectmode);
                                                }
                                        }
+                                       else if (ale->type == ACTTYPE_GPLAYER) {
+                                               select_gpencil_frames(ale->data, selectmode);
+                                       }
                                }
                                break;
                        default: /* any keyframe inside region defined by region */
@@ -3503,6 +3754,9 @@ void borderselect_action (void)
                                                                borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
                                                }
                                        }
+                                       else if (ale->type == ACTTYPE_GPLAYER) {
+                                               borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+                                       }
                                }
                        }
                        
@@ -3533,6 +3787,8 @@ static void mouse_action (int selectmode)
        bActionChannel *achan= NULL;
        bConstraintChannel *conchan= NULL;
        IpoCurve *icu= NULL;
+       bGPdata *gpd = NULL;
+       bGPDlayer *gpl = NULL;
        TimeMarker *marker, *pmarker;
        
        void *act_channel;
@@ -3543,6 +3799,7 @@ static void mouse_action (int selectmode)
        data = get_action_context(&datatype);
        if (data == NULL) return;
        if (datatype == ACTCONT_ACTION) act= (bAction *)data;
+       if (datatype == ACTCONT_GPENCIL) gpd= (bGPdata *)data;
 
        act_channel= get_nearest_action_key(&selx, &sel, &act_type, &achan);
        marker= find_nearest_marker(SCE_MARKERS, 1);
@@ -3615,6 +3872,9 @@ static void mouse_action (int selectmode)
                        case ACTTYPE_GROUP:
                                agrp= (bActionGroup *)act_channel;
                                break;
+                       case ACTTYPE_GPLAYER:
+                               gpl= (bGPDlayer *)act_channel;
+                               break;
                        default:
                                return;
                }
@@ -3638,6 +3898,13 @@ static void mouse_action (int selectmode)
                                        set_active_actiongroup(act, agrp, 1);
                                }
                        }
+                       else if (datatype == ACTCONT_GPENCIL) {
+                               deselect_action_channels(0);
+                               
+                               /* Highlight gpencil layer */
+                               gpl->flag |= GP_LAYER_SELECT;
+                               gpencil_layer_setactive(gpd, gpl);
+                       }
                }
                
                if (icu)
@@ -3654,6 +3921,8 @@ static void mouse_action (int selectmode)
                                        select_ipo_key(conchan->ipo, selx, selectmode);
                        }
                }
+               else if (gpl)
+                       select_gpencil_frame(gpl, selx, selectmode);
                
                std_rmouse_transform(transform_action_keys);
                
@@ -3670,6 +3939,7 @@ static void mouse_action (int selectmode)
 static void mouse_actionchannels (short mval[])
 {
        bAction *act= G.saction->action;
+       bGPdata *gpd= G.saction->gpd;
        void *data, *act_channel;
        short datatype, chantype;
        
@@ -3816,6 +4086,24 @@ static void mouse_actionchannels (short mval[])
                                }
                        }
                                break;
+               case ACTTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl= (bGPDlayer *)act_channel;
+                               
+                               if (mval[0] >= (NAMEWIDTH-16)) {
+                                       /* toggle lock */
+                                       gpl->flag ^= GP_LAYER_LOCKED;
+                               }
+                               else if (mval[0] >= (NAMEWIDTH-32)) {
+                                       /* toggle hide */
+                                       gpl->flag ^= GP_LAYER_HIDE;
+                               }
+                               else {
+                                       /* select/deselect */
+                                       select_gplayer_channel(gpd, gpl, SELECT_INVERT);
+                               }
+                       }
+                               break;
                default:
                        return;
        }
@@ -4482,7 +4770,7 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                case RIGHTMOUSE:
                        /* Clicking in the channel area */
                        if ((G.v2d->mask.xmin) && (mval[0] < NAMEWIDTH)) {
-                               if (datatype == ACTCONT_ACTION) {
+                               if (ELEM(datatype, ACTCONT_ACTION, ACTCONT_GPENCIL)) {
                                        /* mouse is over action channels */
                                        if (G.qual == LR_CTRLKEY)
                                                numbuts_action();
@@ -4832,8 +5120,12 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                case DELKEY:
                case XKEY:
                        if (okee("Erase selected")) {
-                               if (mval[0] < NAMEWIDTH)
-                                       delete_action_channels();
+                               if (mval[0] < NAMEWIDTH) {
+                                       if (datatype == ACTCONT_ACTION)
+                                               delete_action_channels();
+                                       else if (datatype == ACTCONT_GPENCIL)
+                                               delete_gpencil_layers();
+                               }
                                else
                                        delete_action_keys();
                                
diff --git a/source/blender/src/editaction_gpencil.c b/source/blender/src/editaction_gpencil.c
new file mode 100644 (file)
index 0000000..b91c5a8
--- /dev/null
@@ -0,0 +1,549 @@
+/**
+ * $Id: editaction_gpencil.c 14881 2008-05-18 10:41:42Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_listBase.h"
+#include "DNA_action_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_view2d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+#include "BKE_ipo.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_butspace.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_toets.h"
+
+#include "BIF_editaction.h"
+#include "BSE_editaction_types.h"
+
+#include "BDR_gpencil.h"
+#include "BIF_drawgpencil.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+#include "butspace.h"
+
+#include "PIL_time.h"                  /* sleep                                */
+#include "mydevice.h"
+
+/* ***************************************** */
+/* NOTE ABOUT THIS FILE:
+ *     This file contains code for editing Grease Pencil data in the Action Editor
+ *     as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
+ *     Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
+ */
+/* ***************************************** */
+/* Generics - Loopers */
+
+/* Loops over the gp-frames for a gp-layer, and applies the given callback */
+short gplayer_frames_looper (bGPDlayer *gpl, short (*gpf_cb)(bGPDframe *))
+{
+       bGPDframe *gpf;
+       
+       /* error checker */
+       if (gpl == NULL)
+               return 0;
+       
+       /* do loop */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               /* execute callback */
+               if (gpf_cb(gpf))
+                       return 1;
+       }
+               
+       /* nothing to return */
+       return 0;
+}
+
+/* ****************************************** */
+/* Data Conversion Tools */
+
+/* make a listing all the gp-frames in a layer as cfraelems */
+void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel)
+{
+       bGPDframe *gpf;
+       CfraElem *ce;
+       
+       /* error checking */
+       if (ELEM(NULL, gpl, elems))
+               return;
+       
+       /* loop through gp-frames, adding */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
+                       ce= MEM_callocN(sizeof(CfraElem), "CfraElem");
+                       
+                       ce->cfra= gpf->framenum;
+                       ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
+                       
+                       BLI_addtail(elems, ce);
+               }
+       }
+}
+
+/* ***************************************** */
+/* Selection Tools */
+
+/* check if one of the frames in this layer is selected */
+short is_gplayer_frame_selected (bGPDlayer *gpl)
+{
+       bGPDframe *gpf;
+       
+       /* error checking */
+       if (gpl == NULL) 
+               return 0;
+       
+       /* stop at the first one found */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if (gpf->flag & GP_FRAME_SELECT)
+                       return 1;
+       }
+       
+       /* not found */
+       return 0;
+}
+
+/* helper function - select gp-frame based on SELECT_* mode */
+static void gpframe_select (bGPDframe *gpf, short select_mode)
+{
+       switch (select_mode) {
+               case SELECT_ADD:
+                       gpf->flag |= GP_FRAME_SELECT;
+                       break;
+               case SELECT_SUBTRACT:
+                       gpf->flag &= ~GP_FRAME_SELECT;
+                       break;
+               case SELECT_INVERT:
+                       gpf->flag ^= GP_FRAME_SELECT;
+                       break;
+       }
+}
+
+/* set all/none/invert select (like above, but with SELECT_* modes) */
+void select_gpencil_frames (bGPDlayer *gpl, short select_mode)
+{
+       bGPDframe *gpf;
+       
+       /* error checking */
+       if (gpl == NULL) 
+               return;
+               
+       /* handle according to mode */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               gpframe_select(gpf, select_mode);
+       }
+}
+
+/* set all/none/invert select */
+void set_gplayer_frame_selection (bGPDlayer *gpl, short mode)
+{
+       /* error checking */
+       if (gpl == NULL) 
+               return;
+               
+       /* convert mode to select_mode */
+       switch (mode) {
+               case 2:
+                       mode= SELECT_INVERT;
+                       break;
+               case 1:
+                       mode= SELECT_ADD;
+                       break;
+               case 0:
+                       mode= SELECT_SUBTRACT;
+                       break;
+               default:
+                       return;
+       }
+       
+       /* now call the standard function */
+       select_gpencil_frames (gpl, mode);
+}
+
+void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode)
+{
+       bGPDframe *gpf;
+   
+       /* search through frames for a match */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if (gpf->framenum == selx)
+                       gpframe_select(gpf, select_mode);
+       }
+}
+
+void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode)
+{
+       bGPDframe *gpf;
+       
+       /* only select those frames which are in bounds */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if (IN_RANGE(gpf->framenum, min, max))
+                       gpframe_select(gpf, select_mode);
+       }
+}
+
+
+/* De-selects or inverts the selection of Layers for a grease-pencil block
+ *     mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all 
+ */
+void deselect_gpencil_layers (bGPdata *gpd, short mode)
+{
+       ListBase act_data = {NULL, NULL};
+       bActListElem *ale;
+       int filter, sel=1;
+       
+       /* filter data */
+       filter= ACTFILTER_VISIBLE;
+       actdata_filter(&act_data, filter, gpd, ACTCONT_GPENCIL);
+       
+       /* See if we should be selecting or deselecting */
+       if (mode == 1) {
+               for (ale= act_data.first; ale; ale= ale->next) {
+                       if (sel == 0) 
+                               break;
+                       
+                       if (ale->flag & GP_LAYER_SELECT)
+                               sel= 0;
+               }
+       }
+       else
+               sel= 0;
+               
+       /* Now set the flags */
+       for (ale= act_data.first; ale; ale= ale->next) {
+               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+               
+               if (mode == 2)
+                       gpl->flag ^= GP_LAYER_SELECT;
+               else if (sel)
+                       gpl->flag |= GP_LAYER_SELECT;
+               else
+                       gpl->flag &= ~GP_LAYER_SELECT;
+                       
+               gpl->flag &= ~GP_LAYER_ACTIVE;
+       }
+       
+       /* Cleanup */
+       BLI_freelistN(&act_data);
+}
+
+/* ***************************************** */
+/* Frame Editing Tools */
+
+void delete_gpencil_layers (void)
+{
+       ListBase act_data = {NULL, NULL};
+       bActListElem *ale, *next;
+       bGPdata *gpd;
+       void *data;
+       short datatype;
+       int filter;
+       
+       /* determine what type of data we are operating on */
+       data = get_action_context(&datatype);
+       if (data == NULL) return;
+       if (datatype != ACTCONT_GPENCIL) return;
+       gpd= (bGPdata *)data;
+       
+       /* filter data */
+       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
+       actdata_filter(&act_data, filter, data, datatype);
+       
+       /* clean up grease-pencil layers */
+       for (ale= act_data.first; ale; ale= next) {
+               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+               next= ale->next;
+               
+               /* free layer and its data */
+               if (SEL_GPL(gpl)) {
+                       free_gpencil_frames(gpl);
+                       BLI_freelinkN(&gpd->layers, gpl);
+               }
+               
+               /* free temp memory */
+               BLI_freelinkN(&act_data, ale);
+       }
+       
+       BIF_undo_push("Delete GPencil Layers");
+       allspace(REDRAWVIEW3D, 0);
+       allqueue(REDRAWACTION, 0);
+}
+
+/* Delete selected frames */
+void delete_gplayer_frames (bGPDlayer *gpl)
+{
+       bGPDframe *gpf, *gpfn;
+       
+       /* error checking */
+       if (gpl == NULL)
+               return;
+               
+       /* check for frames to delete */
+       for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+               gpfn= gpf->next;
+               
+               if (gpf->flag & GP_FRAME_SELECT)
+                       gpencil_layer_delframe(gpl, gpf);
+       }
+}
+
+/* Duplicate selected frames from given gp-layer */
+void duplicate_gplayer_frames (bGPDlayer *gpl)
+{
+       bGPDframe *gpf, *gpfn;
+       
+       /* error checking */
+       if (gpl == NULL)
+               return;
+       
+       /* duplicate selected frames  */
+       for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+               gpfn= gpf->next;
+               
+               /* duplicate this frame */
+               if (gpf->flag & GP_FRAME_SELECT) {
+                       bGPDframe *gpfd; 
+                       bGPDstroke *gps;
+                       
+                       /* duplicate frame, and deselect self */
+                       gpfd= MEM_dupallocN(gpf);
+                       gpf->flag &= ~GP_FRAME_SELECT;
+                       
+                       /* duplicate list of strokes too */
+                       duplicatelist(&gpfd->strokes, &gpf->strokes);
+                       
+                       /* dupalloc only makes another copy of mem, but doesn't adjust pointers */
+                       for (gps= gpfd->strokes.first; gps; gps= gps->next) {
+                               gps->points= MEM_dupallocN(gps->points);
+                       }
+                       
+                       BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
+               }
+       }
+}
+
+/* -------------------------------------- */
+/* Snap Tools */
+
+static short snap_gpf_nearest (bGPDframe *gpf)
+{
+       if (gpf->flag & GP_FRAME_SELECT)
+               gpf->framenum= (int)(floor(gpf->framenum+0.5));
+       return 0;
+}
+
+static short snap_gpf_nearestsec (bGPDframe *gpf)
+{
+       float secf = FPS;
+       if (gpf->flag & GP_FRAME_SELECT)
+               gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf);
+       return 0;
+}
+
+static short snap_gpf_cframe (bGPDframe *gpf)
+{
+       if (gpf->flag & GP_FRAME_SELECT)
+               gpf->framenum= (int)CFRA;
+       return 0;
+}
+
+static short snap_gpf_nearmarker (bGPDframe *gpf)
+{
+       if (gpf->flag & GP_FRAME_SELECT)
+               gpf->framenum= (int)find_nearest_marker_time(gpf->framenum);
+       return 0;
+}
+
+
+/* snap selected frames to ... */
+void snap_gplayer_frames (bGPDlayer *gpl, short mode)
+{
+       switch (mode) {
+               case 1: /* snap to nearest frame */
+                       gplayer_frames_looper(gpl, snap_gpf_nearest);
+                       break;
+               case 2: /* snap to current frame */
+                       gplayer_frames_looper(gpl, snap_gpf_cframe);
+                       break;
+               case 3: /* snap to nearest marker */
+                       gplayer_frames_looper(gpl, snap_gpf_nearmarker);
+                       break;
+               case 4: /* snap to nearest second */
+                       gplayer_frames_looper(gpl, snap_gpf_nearestsec);
+                       break;
+               default: /* just in case */
+                       gplayer_frames_looper(gpl, snap_gpf_nearest);
+                       break;
+       }
+}
+
+/* -------------------------------------- */
+/* Mirror Tools */
+
+static short mirror_gpf_cframe (bGPDframe *gpf)
+{
+       float diff;
+       
+       if (gpf->flag & GP_FRAME_SELECT) {
+               diff= ((float)CFRA - gpf->framenum);
+               gpf->framenum= ((float)CFRA + diff);
+       }
+       
+       return 0;
+}
+
+static short mirror_gpf_yaxis (bGPDframe *gpf)
+{
+       float diff;
+       
+       if (gpf->flag & GP_FRAME_SELECT) {
+               diff= (0.0f - gpf->framenum);
+               gpf->framenum= (0.0f + diff);
+       }
+       
+       return 0;
+}
+
+static short mirror_gpf_xaxis (bGPDframe *gpf)
+{
+       float diff;
+       
+       if (gpf->flag & GP_FRAME_SELECT) {
+               diff= (0.0f - gpf->framenum);
+               gpf->framenum= (0.0f + diff);
+       }
+       
+       return 0;
+}
+
+static short mirror_gpf_marker (bGPDframe *gpf)
+{
+       static TimeMarker *marker;
+       static short initialised = 0;
+       float diff;
+       
+       /* In order for this mirror function to work without
+        * any extra arguments being added, we use the case
+        * of bezt==NULL to denote that we should find the 
+        * marker to mirror over. The static pointer is safe
+        * to use this way, as it will be set to null after 
+        * each cycle in which this is called.
+        */
+       
+       if (gpf) {
+               /* mirroring time */
+               if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
+                       diff= (marker->frame - gpf->framenum);
+                       gpf->framenum= (marker->frame + diff);
+               }
+       }
+       else {
+               /* initialisation time */
+               if (initialised) {
+                       /* reset everything for safety */
+                       marker = NULL;
+                       initialised = 0;
+               }
+               else {
+                       /* try to find a marker */
+                       for (marker= G.scene->markers.first; marker; marker=marker->next) {
+                               if (marker->flag & SELECT) {
+                                       initialised = 1;
+                                       break;
+                               }
+                       }
+                       
+                       if (initialised == 0) 
+                               marker = NULL;
+               }
+       }
+       
+       return 0;
+}
+
+
+/* mirror selected gp-frames on... */
+void mirror_gplayer_frames (bGPDlayer *gpl, short mode)
+{
+       switch (mode) {
+               case 1: /* mirror over current frame */
+                       gplayer_frames_looper(gpl, mirror_gpf_cframe);
+                       break;
+               case 2: /* mirror over frame 0 */
+                       gplayer_frames_looper(gpl, mirror_gpf_yaxis);
+                       break;
+               case 3: /* mirror over value 0 */
+                       gplayer_frames_looper(gpl, mirror_gpf_xaxis);
+                       break;
+               case 4: /* mirror over marker */
+                       mirror_gpf_marker(NULL);
+                       gplayer_frames_looper(gpl, mirror_gpf_marker);
+                       mirror_gpf_marker(NULL);
+                       break;
+               default: /* just in case */
+                       gplayer_frames_looper(gpl, mirror_gpf_yaxis);
+                       break;
+       }
+}
+
+/* ***************************************** */
index 4c7334c55e06c235d3dc11fb6ecc96d2ea88c286..5c137e67c1a7edc9e1d4fb7cca7323082a5cdc94 100644 (file)
@@ -82,6 +82,7 @@
 #include "BLI_storage_types.h"
 
 #include "BDR_editobject.h"
+#include "BDR_gpencil.h"
 
 #include "RE_pipeline.h"
 #include "IMB_imbuf_types.h"
@@ -2305,6 +2306,7 @@ static int node_uiDoBlocks(ScrArea *sa, short event)
        SpaceNode *snode= sa->spacedata.first;
        ListBase *lb= &sa->uiblocks;
        ListBase listb= *lb;
+       uiBlock *block;
        bNode *node;
        rctf rect;
        void *prev, *next;
@@ -2319,13 +2321,36 @@ static int node_uiDoBlocks(ScrArea *sa, short event)
                return UI_NOTHING;
        }
        
+       /* evil hack: try to do grease-pencil floating panel (like for nodes) */
+       block= uiGetBlock("nodes_panel_gpencil", sa);
+       if (block) {
+               /* try to process events here... if failed, just carry on */
+                       /* when there's menus, the prev pointer becomes zero! */
+               prev= ((struct Link *)block)->prev;
+               next= ((struct Link *)block)->next;
+               ((struct Link *)block)->prev= NULL;
+               ((struct Link *)block)->next= NULL;
+               
+               lb->first= lb->last= block;
+               retval= uiDoBlocks(lb, event, 1);
+               
+               ((struct Link *)block)->prev= prev;
+               ((struct Link *)block)->next= next;
+               
+               *lb= listb;
+               
+               /* if something happened, get the heck outta here */
+               if (retval != UI_NOTHING)
+                       return retval;
+       }
+       
+       
        rect.xmin -= 2.0f;
        rect.ymin -= 2.0f;
        rect.xmax = rect.xmin + 4.0f;
        rect.ymax = rect.ymin + 4.0f;
        
        for(node= snode->edittree->nodes.first; node; node= node->next) {
-               uiBlock *block;
                char str[32];
                
                /* retreive unique block name, see also drawnode.c */
@@ -2369,14 +2394,16 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        if(snode->nodetree==NULL) return;
        
        if(val) {
-
-               if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;  
-
+               if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;
+               
                fromlib= (snode->id && snode->id->lib);
                
                switch(event) {
                case LEFTMOUSE:
-                       if(fromlib) {
+                       if(gpencil_do_paint(sa)) {
+                               return;
+                       }
+                       else if(fromlib) {
                                if(node_mouse_groupheader(snode)==0)
                                        node_mouse_select(snode, event);
                        }
diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c
new file mode 100644 (file)
index 0000000..fa32b0a
--- /dev/null
@@ -0,0 +1,1290 @@
+/**
+ * $Id: gpencil.c 14881 2008-05-18 10:41:42Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_butspace.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_toets.h"
+
+#include "BDR_gpencil.h"
+#include "BIF_drawgpencil.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+
+#include "PIL_time.h"                  /* sleep                                */
+#include "mydevice.h"
+
+/* ************************************************** */
+/* GENERAL STUFF */
+
+/* --------- Memory Management ------------ */
+
+/* Free strokes belonging to a gp-frame */
+void free_gpencil_strokes (bGPDframe *gpf)
+{
+       bGPDstroke *gps, *gpsn;
+       
+       /* error checking */
+       if (gpf == NULL) return;
+       
+       /* free strokes */
+       for (gps= gpf->strokes.first; gps; gps= gpsn) {
+               gpsn= gps->next;
+               
+               /* free stroke memory arrays, then stroke itself */
+               MEM_freeN(gps->points);
+               BLI_freelinkN(&gpf->strokes, gps);
+       }
+}
+
+/* Free all of a gp-layer's frames */
+void free_gpencil_frames (bGPDlayer *gpl)
+{
+       bGPDframe *gpf, *gpfn;
+       
+       /* error checking */
+       if (gpl == NULL) return;
+       
+       /* free frames */
+       for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+               gpfn= gpf->next;
+               
+               /* free strokes and their associated memory */
+               free_gpencil_strokes(gpf);
+               BLI_freelinkN(&gpl->frames, gpf);
+       }
+}
+
+/* Free all of the gp-layers for a viewport (list should be &G.vd->gpd or so) */
+void free_gpencil_layers (ListBase *list) 
+{
+       bGPDlayer *gpl, *gpln;
+       
+       /* error checking */
+       if (list == NULL) return;
+       
+       /* delete layers*/
+       for (gpl= list->first; gpl; gpl= gpln) {
+               gpln= gpl->next;
+               
+               /* free layers and their data */
+               free_gpencil_frames(gpl);
+               BLI_freelinkN(list, gpl);
+       }
+}
+
+/* Free gp-data and all it's related data */
+void free_gpencil_data (bGPdata *gpd)
+{
+       /* free layers then data itself */
+       free_gpencil_layers(&gpd->layers);
+       MEM_freeN(gpd);
+}
+
+/* -------- Container Creation ---------- */
+
+/* add a new gp-frame to the given layer */
+bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
+{
+       bGPDframe *gpf, *gf;
+       short state=0;
+       
+       /* error checking */
+       if ((gpl == NULL) || (cframe <= 0))
+               return NULL;
+               
+       /* allocate memory for this frame */
+       gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+       gpf->framenum= cframe;
+       
+       /* find appropriate place to add frame */
+       if (gpl->frames.first) {
+               for (gf= gpl->frames.first; gf; gf= gf->next) {
+                       /* check if frame matches one that is supposed to be added */
+                       if (gf->framenum == cframe) {
+                               state= -1;
+                               break;
+                       }
+                       
+                       /* if current frame has already exceeded the frame to add, add before */
+                       if (gf->framenum > cframe) {
+                               BLI_insertlinkbefore(&gpl->frames, gf, gpf);
+                               state= 1;
+                               break;
+                       }
+               }
+       }
+       
+       /* check whether frame was added successfully */
+       if (state == -1) {
+               MEM_freeN(gpf);
+               printf("Error: frame (%d) existed already for this layer \n", cframe);
+       }
+       else if (state == 0) {
+               /* add to end then! */
+               BLI_addtail(&gpl->frames, gpf);
+       }
+       
+       /* return frame */
+       return gpf;
+}
+
+/* add a new gp-layer and make it the active layer */
+bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       
+       /* check that list is ok */
+       if (gpd == NULL)
+               return NULL;
+               
+       /* allocate memory for frame and add to end of list */
+       gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
+       
+       /* add to datablock */
+       BLI_addtail(&gpd->layers, gpl);
+       
+       /* set basic settings */
+       gpl->color[3]= 1.0f;
+       gpl->thickness = 1;
+       
+       /* auto-name */
+       sprintf(gpl->info, "GP_Layer");
+       BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
+       
+       /* make this one the active one */
+       gpencil_layer_setactive(gpd, gpl);
+       
+       /* return layer */
+       return gpl;
+}
+
+/* add a new gp-datablock */
+bGPdata *gpencil_data_addnew (void)
+{
+       bGPdata *gpd;
+       
+       /* allocate memory for a new block */
+       gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
+       
+       /* initial settings */
+               /* it is quite useful to be able to see this info, so on by default */
+       gpd->flag = GP_DATA_DISPINFO;
+       
+       return gpd;
+}
+
+/* -------- Data Duplication ---------- */
+
+/* make a copy of a given gpencil datablock */
+bGPdata *gpencil_data_duplicate (bGPdata *src)
+{
+       bGPdata *dst;
+       bGPDlayer *gpld, *gpls;
+       bGPDframe *gpfd, *gpfs;
+       bGPDstroke *gps;
+       
+       /* error checking */
+       if (src == NULL)
+               return NULL;
+       
+       /* make a copy of the base-data */
+       dst= MEM_dupallocN(src);
+       
+       /* copy layers */
+       duplicatelist(&dst->layers, &src->layers);
+       
+       for (gpld=dst->layers.first, gpls=src->layers.first; gpld && gpls; 
+                gpld=gpld->next, gpls=gpls->next) 
+       {
+               /* copy frames */
+               duplicatelist(&gpld->frames, &gpls->frames);
+               
+               for (gpfd=gpld->frames.first, gpfs=gpls->frames.first; gpfd && gpfs;
+                        gpfd=gpfd->next, gpfs=gpfs->next) 
+               {
+                       /* copy strokes */
+                       duplicatelist(&gpfd->strokes, &gpfs->strokes);
+                       
+                       for (gps= gpfd->strokes.first; gps; gps= gps->next) 
+                       {
+                               gps->points= MEM_dupallocN(gps->points);
+                       }
+               }
+       }
+       
+       /* return new */
+       return dst;
+}
+
+/* ----------- GP-Datablock API ------------- */
+
+/* get the appropriate bGPdata from the active/given context */
+bGPdata *gpencil_data_getactive (ScrArea *sa)
+{
+       /* error checking */
+       if ((sa == NULL) && (curarea == NULL))
+               return NULL;
+       if (sa == NULL)
+               sa= curarea;
+               
+       /* handle depending on spacetype */
+       switch (sa->spacetype) {
+               case SPACE_VIEW3D:
+               {
+                       View3D *v3d= sa->spacedata.first;
+                       return v3d->gpd;
+               }
+                       break;
+               case SPACE_NODE:
+               {
+                       SpaceNode *snode= sa->spacedata.first;
+                       return snode->gpd;
+               }
+                       break;
+               case SPACE_SEQ:
+               {
+                       SpaceSeq *sseq= sa->spacedata.first;
+                       
+                       /* only applicable for "Image Preview" mode */
+                       if (sseq->mainb)
+                               return sseq->gpd;
+               }
+                       break;
+       }
+       
+       /* nothing found */
+       return NULL;
+}
+
+/* set bGPdata for the active/given context, and return success/fail */
+short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
+{
+       /* error checking */
+       if ((sa == NULL) && (curarea == NULL))
+               return 0;
+       if (gpd == NULL)
+               return 0;
+       if (sa == NULL)
+               sa= curarea;
+       
+       /* handle depending on spacetype */
+       // TODO: someday we should have multi-user data, so no need to loose old data
+       switch (sa->spacetype) {
+               case SPACE_VIEW3D:
+               {
+                       View3D *v3d= sa->spacedata.first;
+                       
+                       /* free the existing block */
+                       if (v3d->gpd)
+                               free_gpencil_data(v3d->gpd);
+                       v3d->gpd= gpd;
+                       
+                       return 1;
+               }
+                       break;
+               case SPACE_NODE:
+               {
+                       SpaceNode *snode= sa->spacedata.first;
+                       
+                       /* free the existing block */
+                       if (snode->gpd)
+                               free_gpencil_data(snode->gpd);
+                       snode->gpd= gpd;
+                       
+                       /* set special settings */
+                       gpd->flag |= GP_DATA_VIEWALIGN;
+                       
+                       return 1;
+               }
+                       break;
+               case SPACE_SEQ:
+               {
+                       SpaceSeq *sseq= sa->spacedata.first;
+                       
+                       /* only applicable if right mode */
+                       if (sseq->mainb) {
+                               /* free the existing block */
+                               if (sseq->gpd)
+                                       free_gpencil_data(sseq->gpd);
+                               sseq->gpd= gpd;
+                               
+                               return 1;
+                       }
+               }
+                       break;
+       }
+       
+       /* failed to add */
+       return 0;
+}
+
+/* Find gp-data destined for editing in animation editor (for editing time) */
+bGPdata *gpencil_data_getetime (bScreen *sc)
+{
+       bGPdata *gpd= NULL;
+       ScrArea *sa;
+       
+       /* error checking */
+       if (sc == NULL)
+               return NULL;
+       
+       /* search through areas, checking if an appropriate gp-block is available 
+        * (this assumes that only one will have the active flag set)
+        */
+       for (sa= sc->areabase.first; sa; sa= sa->next) {
+               /* handle depending on space type */
+               switch (sa->spacetype) {
+                       case SPACE_VIEW3D: /* 3d-view */
+                       {
+                               View3D *v3d= sa->spacedata.first;
+                               gpd= v3d->gpd;
+                       }
+                               break;
+                       case SPACE_NODE: /* Node Editor */
+                       {
+                               SpaceNode *snode= sa->spacedata.first;
+                               gpd= snode->gpd;
+                       }
+                               break;
+                       case SPACE_SEQ: /* Sequence Editor - Image Preview */
+                       {
+                               SpaceSeq *sseq= sa->spacedata.first;
+                               
+                               if (sseq->mainb)
+                                       gpd= sseq->gpd;
+                               else
+                                       gpd= NULL;
+                       }
+                               break;
+                               
+                       default: /* unsupported space-type */
+                               gpd= NULL;
+                               break;
+               }
+               
+               /* check if ok */
+               if ((gpd) && (gpd->flag & GP_DATA_EDITTIME))
+                       return gpd;
+       }
+       
+       /* didn't find a match */
+       return NULL;
+}
+
+/* make sure only the specified view can have gp-data for time editing 
+ *     - gpd can be NULL, if we wish to make sure no gp-data is being edited
+ */
+void gpencil_data_setetime (bScreen *sc, bGPdata *gpd)
+{
+       bGPdata *gpdn= NULL;
+       ScrArea *sa;
+       
+       /* error checking */
+       if (sc == NULL)
+               return;
+       
+       /* search through areas, checking if an appropriate gp-block is available 
+        * (this assumes that only one will have the active flag set)
+        */
+       for (sa= sc->areabase.first; sa; sa= sa->next) {
+               /* handle depending on space type */
+               switch (sa->spacetype) {
+                       case SPACE_VIEW3D: /* 3d-view */
+                       {
+                               View3D *v3d= sa->spacedata.first;
+                               gpdn= v3d->gpd;
+                       }
+                               break;
+                       case SPACE_NODE: /* Node Editor */
+                       {
+                               SpaceNode *snode= sa->spacedata.first;
+                               gpdn= snode->gpd;
+                       }
+                               break;
+                       case SPACE_SEQ: /* Sequence Editor - Image Preview */
+                       {
+                               SpaceSeq *sseq= sa->spacedata.first;
+                               gpdn= sseq->gpd;
+                       }
+                               break;
+                               
+                       default: /* unsupported space-type */
+                               gpdn= NULL;
+                               break;
+               }
+               
+               /* clear flag if a gp-data block found */
+               if (gpdn)
+                       gpdn->flag &= ~GP_DATA_EDITTIME;
+       }
+       
+       /* set active flag for this block (if it is provided) */
+       if (gpd)
+               gpd->flag |= GP_DATA_EDITTIME;
+}
+
+/* -------- GP-Frame API ---------- */
+
+/* delete the last stroke of the given frame */
+void gpencil_frame_delete_laststroke (bGPDframe *gpf)
+{
+       bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
+       
+       /* error checking */
+       if (ELEM(NULL, gpf, gps))
+               return;
+       
+       /* free the stroke and its data */
+       MEM_freeN(gps->points);
+       BLI_freelinkN(&gpf->strokes, gps);
+}
+
+/* -------- GP-Layer API ---------- */
+
+/* get the appropriate gp-frame from a given layer
+ *     - this sets the layer's actframe var (if allowed to)
+ *     - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
+ */
+bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
+{
+       bGPDframe *gpf = NULL;
+       short found = 0;
+       
+       /* error checking */
+       if (gpl == NULL) return NULL;
+       if (cframe <= 0) cframe = 1;
+       
+       /* check if there is already an active frame */
+       if (gpl->actframe) {
+               gpf= gpl->actframe;
+               
+               /* do not allow any changes to layer's active frame if layer is locked */
+               if (gpl->flag & GP_LAYER_LOCKED)
+                       return gpf;
+               /* do not allow any changes to actframe if frame has painting tag attached to it */
+               if (gpf->flag & GP_FRAME_PAINT) 
+                       return gpf;
+               
+               /* try to find matching frame */
+               if (gpf->framenum < cframe) {
+                       for (; gpf; gpf= gpf->next) {
+                               if (gpf->framenum == cframe) {
+                                       found= 1;
+                                       break;
+                               }
+                               else if ((gpf->next) && (gpf->next->framenum > cframe)) {
+                                       found= 1;
+                                       break;
+                               }
+                       }
+                       
+                       /* set the appropriate frame */
+                       if (addnew) {
+                               if ((found) && (gpf->framenum == cframe))
+                                       gpl->actframe= gpf;
+                               else
+                                       gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+                       }
+                       else if (found)
+                               gpl->actframe= gpf;
+                       else
+                               gpl->actframe= gpl->frames.last;
+               }
+               else {
+                       for (; gpf; gpf= gpf->prev) {
+                               if (gpf->framenum <= cframe) {
+                                       found= 1;
+                                       break;
+                               }
+                       }
+                       
+                       /* set the appropriate frame */
+                       if (addnew) {
+                               if ((found) && (gpf->framenum == cframe))
+                                       gpl->actframe= gpf;
+                               else
+                                       gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+                       }
+                       else if (found)
+                               gpl->actframe= gpf;
+                       else
+                               gpl->actframe= gpl->frames.first;
+               }
+       }
+       else if (gpl->frames.first) {
+               /* check which of the ends to start checking from */
+               const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
+               const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
+               
+               if (abs(cframe-first) > abs(cframe-last)) {
+                       /* find gp-frame which is less than or equal to cframe */
+                       for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
+                               if (gpf->framenum <= cframe) {
+                                       found= 1;
+                                       break;
+                               }
+                       }
+               }
+               else {
+                       /* find gp-frame which is less than or equal to cframe */
+                       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                               if (gpf->framenum <= cframe) {
+                                       found= 1;
+                                       break;
+                               }
+                       }
+               }
+               
+               /* set the appropriate frame */
+               if (addnew) {
+                       if ((found) && (gpf->framenum == cframe))
+                               gpl->actframe= gpf;
+                       else
+                               gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+               }
+               else if (found)
+                       gpl->actframe= gpf;
+               else {
+                       /* unresolved errogenous situation! */
+                       printf("Error: cannot find appropriate gp-frame \n");
+               }
+       }
+       else {
+               /* currently no frames (add if allowed to) */
+               if (addnew)
+                       gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+               else {
+                       /* don't do anything... this may be when no frames yet! */
+               }
+       }
+       
+       /* return */
+       return gpl->actframe;
+}
+
+/* delete the given frame from a layer */
+void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
+{
+       /* error checking */
+       if (ELEM(NULL, gpl, gpf))
+               return;
+               
+       /* free the frame and its data */
+       free_gpencil_strokes(gpf);
+       BLI_freelinkN(&gpl->frames, gpf);
+       gpl->actframe = NULL;
+}
+
+/* get the active gp-layer for editing */
+bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       
+       /* error checking */
+       if (ELEM(NULL, gpd, gpd->layers.first))
+               return NULL;
+               
+       /* loop over layers until found (assume only one active) */
+       for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
+               if (gpl->flag & GP_LAYER_ACTIVE)
+                       return gpl;
+       }
+       
+       /* no active layer found */
+       return NULL;
+}
+
+/* set the active gp-layer */
+void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
+{
+       bGPDlayer *gpl;
+       
+       /* error checking */
+       if (ELEM3(NULL, gpd, gpd->layers.first, active))
+               return;
+               
+       /* loop over layers deactivating all */
+       for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
+               gpl->flag &= ~GP_LAYER_ACTIVE;
+       
+       /* set as active one */
+       active->flag |= GP_LAYER_ACTIVE;
+}
+
+/* delete the active gp-layer */
+void gpencil_layer_delactive (bGPdata *gpd)
+{
+       bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+       
+       /* error checking */
+       if (ELEM(NULL, gpd, gpl)) 
+               return;
+       
+       /* free layer */        
+       free_gpencil_frames(gpl);
+       BLI_freelinkN(&gpd->layers, gpl);
+
+}
+
+/* ************************************************** */
+/* GREASE-PENCIL EDITING MODE - Tools */
+
+/* --------- Data Deletion ---------- */
+
+/* delete the last stroke on the active layer */
+void gpencil_delete_laststroke (bGPdata *gpd)
+{
+       bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+       bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+       
+       gpencil_frame_delete_laststroke(gpf);
+}
+
+/* delete the active frame */
+void gpencil_delete_actframe (bGPdata *gpd)
+{
+       bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+       bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+       
+       gpencil_layer_delframe(gpl, gpf);
+}
+
+
+
+/* delete various grase-pencil elements 
+ *     mode:   1 - last stroke
+ *                     2 - active frame
+ *                     3 - active layer
+ */
+void gpencil_delete_operation (short mode) // unused
+{
+       bGPdata *gpd;
+       
+       /* get datablock to work on */
+       gpd= gpencil_data_getactive(NULL);
+       if (gpd == NULL) return;
+       
+       switch (mode) {
+               case 1: /* last stroke */
+                       gpencil_delete_laststroke(gpd);
+                       break;
+               case 2: /* active frame */
+                       gpencil_delete_actframe(gpd);
+                       break;
+               case 3: /* active layer */
+                       gpencil_layer_delactive(gpd);
+                       break;
+       }
+       
+       /* redraw and undo-push */
+       BIF_undo_push("GPencil Delete");
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+/* display a menu for deleting different grease-pencil elements */
+void gpencil_delete_menu (void) // unused
+{
+       short mode;
+       
+       mode= pupmenu("Erase...%t|Last Stroke%x1|Active Frame%x2|Active Layer%x3");
+       if (mode <= 0) return;
+       
+       gpencil_delete_operation(mode);
+}
+
+/* ************************************************** */
+/* GREASE-PENCIL EDITING MODE - Painting */
+
+/* ---------- 'Globals' and Defines ----------------- */
+
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX   500     
+
+/* ------ */
+
+/* Temporary 'Stroke' Operation data */
+typedef struct tGPsdata {
+       ScrArea *sa;            /* area where painting originated */
+       View2D *v2d;            /* needed for GP_STROKE_2DSPACE */
+       
+       bGPdata *gpd;           /* gp-datablock layer comes from */
+       bGPDlayer *gpl;         /* layer we're working on */
+       bGPDframe *gpf;         /* frame we're working on */
+       
+       short status;           /* current status of painting */
+       short paintmode;        /* mode for painting (L_MOUSE or R_MOUSE for now) */
+} tGPsdata;
+
+/* values for tGPsdata->status */
+enum {
+       GP_STATUS_NORMAL = 0,   /* running normally */
+       GP_STATUS_ERROR,                /* something wasn't correctly set up */
+       GP_STATUS_DONE                  /* painting done */
+};
+
+/* Return flags for adding points to stroke buffer */
+enum {
+       GP_STROKEADD_INVALID    = -2,           /* error occurred - insufficient info to do so */
+       GP_STROKEADD_OVERFLOW   = -1,           /* error occurred - cannot fit any more points */
+       GP_STROKEADD_NORMAL,                            /* point was successfully added */
+       GP_STROKEADD_FULL                                       /* cannot add any more points to buffer */
+};
+
+/* ---------- Stroke Editing ------------ */
+
+/* clear the session buffers (call this before AND after a paint operation) */
+static void gp_session_validatebuffer (tGPsdata *p)
+{
+       bGPdata *gpd= p->gpd;
+       
+       /* clear memory of buffer (or allocate it if starting a new session) */
+       if (gpd->sbuffer)
+               memset(gpd->sbuffer, 0, sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX);
+       else
+               gpd->sbuffer= MEM_callocN(sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+       
+       /* reset indices */
+       gpd->sbuffer_size = 0;
+       
+       /* reset flags */
+       gpd->sbuffer_sflag= 0;
+}
+
+/* init new painting session */
+static void gp_session_initpaint (tGPsdata *p)
+{
+       /* clear previous data (note: is on stack) */
+       memset(p, 0, sizeof(tGPsdata));
+       
+       /* make sure the active view (at the starting time) is a 3d-view */
+       if (curarea == NULL) {
+               p->status= GP_STATUS_ERROR;
+               if (G.f & G_DEBUG) 
+                       printf("Error: No active view for painting \n");
+               return;
+       }
+       switch (curarea->spacetype) {
+               /* supported views first */
+               case SPACE_VIEW3D:
+               {
+                       View3D *v3d= curarea->spacedata.first;
+                       
+                       /* set current area */
+                       p->sa= curarea;
+                       
+                       /* check that gpencil data is allowed to be drawn */
+                       if ((v3d->flag2 & V3D_DISPGP)==0) {
+                               p->status= GP_STATUS_ERROR;
+                               if (G.f & G_DEBUG) 
+                                       printf("Error: In active view, Grease Pencil not shown \n");
+                               return;
+                       }
+               }
+                       break;
+               case SPACE_NODE:
+               {
+                       SpaceNode *snode= curarea->spacedata.first;
+                       
+                       /* set current area */
+                       p->sa= curarea;
+                       p->v2d= &snode->v2d;
+                       
+                       /* check that gpencil data is allowed to be drawn */
+                       if ((snode->flag & SNODE_DISPGP)==0) {
+                               p->status= GP_STATUS_ERROR;
+                               if (G.f & G_DEBUG) 
+                                       printf("Error: In active view, Grease Pencil not shown \n");
+                               return;
+                       }
+               }
+                       break;
+               case SPACE_SEQ:
+               {
+                       SpaceSeq *sseq= curarea->spacedata.first;
+                       
+                       /* set current area */
+                       p->sa= curarea;
+                       p->v2d= &sseq->v2d;
+                       
+                       /* check that gpencil data is allowed to be drawn */
+                       if (sseq->mainb == 0) {
+                               p->status= GP_STATUS_ERROR;
+                               if (G.f & G_DEBUG) 
+                                       printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil \n");
+                               return;
+                       }
+                       if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
+                               p->status= GP_STATUS_ERROR;
+                               if (G.f & G_DEBUG) 
+                                       printf("Error: In active view, Grease Pencil not shown \n");
+                               return;
+                       }
+               }
+                       break;  
+               /* unsupported views */
+               default:
+               {
+                       p->status= GP_STATUS_ERROR;
+                       if (G.f & G_DEBUG) 
+                               printf("Error: Active view not appropriate for Grease Pencil drawing \n");
+                       return;
+               }
+                       break;
+       }
+       
+       /* get gp-data */
+       p->gpd= gpencil_data_getactive(p->sa);
+       if (p->gpd == NULL) {
+               short ok;
+               
+               p->gpd= gpencil_data_addnew();
+               ok= gpencil_data_setactive(p->sa, p->gpd);
+               
+               /* most of the time, the following check isn't needed */
+               if (ok == 0) {
+                       /* free gpencil data as it can't be used */
+                       free_gpencil_data(p->gpd);
+                       p->gpd= NULL;
+                       p->status= GP_STATUS_ERROR;
+                       if (G.f & G_DEBUG) 
+                               printf("Error: Could not assign newly created Grease Pencil data to active area \n");
+                       return;
+               }
+       }
+       
+       /* set edit flags */
+       G.f |= G_GREASEPENCIL;
+       
+       /* clear out buffer (stored in gp-data) in case something contaminated it */
+       gp_session_validatebuffer(p);
+}
+
+/* cleanup after a painting session */
+static void gp_session_cleanup (tGPsdata *p)
+{
+       bGPdata *gpd= p->gpd;
+       
+       /* error checking */
+       if (gpd == NULL)
+               return;
+       
+       /* free stroke buffer */
+       if (gpd->sbuffer) {
+               MEM_freeN(gpd->sbuffer);
+               gpd->sbuffer= NULL;
+       }
+       
+       /* clear flags */
+       gpd->sbuffer_size= 0;
+       gpd->sbuffer_sflag= 0;
+}
+
+/* convert screen-coordinates to buffer-coordinates */
+static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
+{
+       bGPdata *gpd= p->gpd;
+       
+       /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+       if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
+               short mx=mval[0], my=mval[1];
+               float *fp= give_cursor();
+               float dvec[3];
+               
+               /* method taken from editview.c - mouse_cursor() */
+               project_short_noclip(fp, mval);
+               window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+               VecSubf(out, fp, dvec);
+       }
+       
+       /* 2d - on 'canvas' (assume that p->v2d is set) */
+       else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
+               float x, y;
+               
+               areamouseco_to_ipoco(p->v2d, mval, &x, &y);
+               
+               out[0]= x;
+               out[1]= y;
+       }
+       
+       /* 2d - relative to screen (viewport area) */
+       else {
+               out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
+               out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
+       }
+}
+
+/* add current stroke-point to buffer (returns whether point was successfully added) */
+static short gp_stroke_addpoint (tGPsdata *p, short mval[], float pressure)
+{
+       bGPdata *gpd= p->gpd;
+       bGPDspoint *pt;
+       
+       /* check if still room in buffer */
+       if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
+               return GP_STROKEADD_OVERFLOW;
+       
+       
+       /* get pointer to destination point */
+       pt= gpd->sbuffer + gpd->sbuffer_size;
+       
+       /* convert screen-coordinates to appropriate coordinates (and store them) */
+       gp_stroke_convertcoords(p, mval, &pt->x);
+       
+       /* store other settings */
+       pt->pressure= pressure;
+       
+       /* increment counters */
+       gpd->sbuffer_size++;
+       
+       /* check if another operation can still occur */
+       if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
+               return GP_STROKEADD_FULL;
+       else
+               return GP_STROKEADD_NORMAL;
+}
+
+/* smooth a stroke (in buffer) before storing it */
+static void gp_stroke_smooth (tGPsdata *p)
+{
+       bGPdata *gpd= p->gpd;
+       int i=0, cmx=gpd->sbuffer_size;
+       
+       /* don't try if less than 2 points in buffer */
+       if ((cmx <= 2) || (gpd->sbuffer == NULL))
+               return;
+       
+       /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
+       for (i=0; i < gpd->sbuffer_size; i++) {
+               bGPDspoint *pc= (gpd->sbuffer + i);
+               bGPDspoint *pb= (i-1 > 0)?(pc-1):(pc);
+               bGPDspoint *pa= (i-2 > 0)?(pc-2):(pb);
+               bGPDspoint *pd= (i+1 < cmx)?(pc+1):(pc);
+               bGPDspoint *pe= (i+2 < cmx)?(pc+2):(pd);
+               
+               pc->x= (0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
+               pc->y= (0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
+       }
+}
+
+/* make a new stroke from the buffer data */
+static void gp_stroke_newfrombuffer (tGPsdata *p)
+{
+       bGPdata *gpd= p->gpd;
+       bGPDstroke *gps;
+       bGPDspoint *pt, *ptc;
+       int i, totelem;
+       
+       /* get total number of points to allocate space for */
+       totelem = gpd->sbuffer_size;
+       
+       /* exit with error if no valid points from this stroke */
+       if (totelem == 0) {
+               if (G.f & G_DEBUG) 
+                       printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
+               return;
+       }
+       
+       /* allocate memory for a new stroke */
+       gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+       
+       /* allocate enough memory for a continuous array for storage points */
+       pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
+       
+       /* copy appropriate settings for stroke */
+       gps->totpoints= totelem;
+       gps->thickness= p->gpl->thickness;
+       gps->flag= gpd->sbuffer_sflag;
+       
+       /* copy points from the buffer to the stroke */
+       for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
+               memcpy(pt, ptc, sizeof(bGPDspoint));
+               pt++;
+       }
+       
+       /* add stroke to frame */
+       BLI_addtail(&p->gpf->strokes, gps);
+}
+
+/* ---------- 'Paint' Tool ------------ */
+
+/* init new stroke */
+static void gp_paint_initstroke (tGPsdata *p)
+{      
+       /* get active layer (or add a new one if non-existent) */
+       p->gpl= gpencil_layer_getactive(p->gpd);
+       if (p->gpl == NULL)
+               p->gpl= gpencil_layer_addnew(p->gpd);
+       if (p->gpl->flag & GP_LAYER_LOCKED) {
+               p->status= GP_STATUS_ERROR;
+               if (G.f & G_DEBUG)
+                       printf("Error: Cannot paint on locked layer \n");
+               return;
+       }
+               
+       /* get active frame (add a new one if not matching frame) */
+       p->gpf= gpencil_layer_getframe(p->gpl, CFRA, 1);
+       if (p->gpf == NULL) {
+               p->status= GP_STATUS_ERROR;
+               if (G.f & G_DEBUG) 
+                       printf("Error: No frame created (gpencil_paint_init) \n");
+               return;
+       }
+       else
+               p->gpf->flag |= GP_FRAME_PAINT;
+               
+       /* check if points will need to be made in 3d-space */
+       if (p->gpd->flag & GP_DATA_VIEWALIGN) {
+               switch (p->sa->spacetype) {
+                       case SPACE_VIEW3D:
+                       {
+                               float *fp= give_cursor();
+                               initgrabz(fp[0], fp[1], fp[2]);
+                               
+                               p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
+                       }
+                               break;
+                       case SPACE_NODE:
+                       {
+                               p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
+                       }
+                               break;
+                       case SPACE_SEQ:
+                       {
+                               /* for now, this is not applicable here... */
+                       }
+                               break;
+               }
+       }
+}
+
+/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
+static void gp_paint_strokeend (tGPsdata *p)
+{
+       /* sanitize stroke-points in buffer */
+       gp_stroke_smooth(p);
+       
+       /* transfer stroke to frame */
+       gp_stroke_newfrombuffer(p);
+       
+       /* clean up buffer now */
+       gp_session_validatebuffer(p);
+}
+
+/* finish off stroke painting operation */
+static void gp_paint_cleanup (tGPsdata *p)
+{
+       /* finish off a stroke */
+       gp_paint_strokeend(p);
+       
+       /* "unlock" frame */
+       p->gpf->flag &= ~GP_FRAME_PAINT;
+       
+       /* add undo-push so stroke can be undone */
+       /* FIXME: currently disabled, as it's impossible to get this working nice
+        * as gpenci data is on currently screen-level (which isn't saved to undo files)
+        */
+       //BIF_undo_push("GPencil Stroke");
+       
+       /* force redraw after drawing action */
+       force_draw(0);
+}
+
+/* -------- */
+
+/* main call to paint a new stroke */
+short gpencil_paint (short mousebutton)
+{
+       tGPsdata p;
+       short prevmval[2], mval[2];
+       float opressure, pressure;
+       short ok = GP_STROKEADD_NORMAL;
+       
+       /* init paint-data */
+       gp_session_initpaint(&p);
+       if (p.status == GP_STATUS_ERROR) {
+               gp_session_cleanup(&p);
+               return 0;
+       }
+       gp_paint_initstroke(&p);
+       if (p.status == GP_STATUS_ERROR) {
+               gp_session_cleanup(&p);
+               return 0;
+       }
+       
+       /* set cursor to indicate drawing */
+       setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
+       
+       /* init drawing-device settings */
+       getmouseco_areawin(mval);
+       pressure = get_pressure();
+       
+       prevmval[0]= mval[0];
+       prevmval[1]= mval[1];
+       opressure= pressure;
+       
+       /* only allow painting of single 'dots' if: 
+        *      - pressure is not excessive (as it can be on some windows tablets)
+        *      - draw-mode for active datablock is turned on
+        */
+       if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { 
+               gp_stroke_addpoint(&p, mval, pressure);
+       }
+       
+       /* paint loop */
+       do {
+               /* get current user input */
+               getmouseco_areawin(mval);
+               pressure = get_pressure();
+               
+               /* only add current point to buffer if mouse moved (otherwise wait until it does) */
+               if ((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+                       /* try to add point */
+                       ok= gp_stroke_addpoint(&p, mval, pressure);
+                       
+                       /* handle errors while adding point */
+                       if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+                               /* finish off old stroke */
+                               gp_paint_strokeend(&p);
+                               
+                               /* start a new stroke, starting from previous point */
+                               gp_stroke_addpoint(&p, prevmval, opressure);
+                               ok= gp_stroke_addpoint(&p, mval, pressure);
+                       }
+                       else if (ok == GP_STROKEADD_INVALID) {
+                               /* the painting operation cannot continue... */
+                               error("Cannot paint stroke");
+                               p.status = GP_STATUS_ERROR;
+                               
+                               if (G.f & G_DEBUG) 
+                                       printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
+                               break;
+                       }
+                       force_draw(0);
+                       
+                       prevmval[0]= mval[0];
+                       prevmval[1]= mval[1];
+                       opressure= pressure;
+               }
+               else
+                       BIF_wait_for_statechange();
+               
+               /* do mouse checking at the end, so don't check twice, and potentially
+                * miss a short tap 
+                */
+       } while (get_mbut() & mousebutton);
+       
+       /* clear edit flags */
+       G.f &= ~G_GREASEPENCIL;
+       
+       /* restore cursor to indicate end of drawing */
+       setcursor_space(p.sa->spacetype, CURSOR_STD);
+       
+       /* check size of buffer before cleanup, to determine if anything happened here */
+       ok= p.gpd->sbuffer_size;
+       
+       /* cleanup */
+       gp_paint_cleanup(&p);
+       gp_session_cleanup(&p);
+       
+       /* done! return if a stroke was successfully added */
+       return ok;
+}
+
+
+/* All event (loops) handling checking if stroke drawing should be initiated
+ * should call this function.
+ */
+short gpencil_do_paint (ScrArea *sa)
+{
+       bGPdata *gpd = gpencil_data_getactive(sa);
+       short mousebutton = L_MOUSE; /* for now, this is always on L_MOUSE*/
+       short retval= 0;
+       
+       /* check if possible to do painting */
+       if (gpd == NULL) 
+               return 0;
+       
+       /* currently, we will only paint if:
+        *      1. draw-mode on gpd is set (for accessibility reasons)
+        *              (single 'dots' are only available via this method)
+        *      2. if shift-modifier is held + lmb -> 'quick paint'
+        */
+       if (gpd->flag & GP_DATA_EDITPAINT) {
+               /* try to paint */
+               retval = gpencil_paint(mousebutton);
+       }
+       else if (G.qual == LR_SHIFTKEY) {
+               /* try to paint */
+               retval = gpencil_paint(mousebutton);
+       }
+       
+       /* return result of trying to paint */
+       return retval;
+}
+
+/* ************************************************** */
index 9c7046c51115a5c35563975b4a60072856f2900f..50d343ca470b4c210bd865d50dfa015500d3933b 100644 (file)
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
 #include "BIF_editaction.h"
 #include "BIF_interface.h"
+#include "BIF_language.h"
 #include "BIF_poseobject.h"
 #include "BIF_resources.h"
 #include "BIF_screen.h"
@@ -76,6 +79,7 @@
 #include "blendef.h"
 #include "mydevice.h"
 
+/* ------------------------------- */
 /* enums declaring constants that are used as menu event codes  */
 
 enum {
@@ -212,6 +216,16 @@ enum {
        ACTMENU_MARKERS_LOCALMOVE
 };
 
+/* ------------------------------- */
+/* macros for easier state testing (only for use here) */
+
+/* test if active action editor is showing any markers */
+#define G_SACTION_HASMARKERS \
+       ((G.saction->action && G.saction->action->markers.first) \
+        || (G.scene->markers.first))
+
+/* ------------------------------- */
+
 void do_action_buttons(unsigned short event)
 {
        Object *ob= OBACT;
@@ -398,32 +412,41 @@ static uiBlock *action_viewmenu(void *arg_unused)
        
        uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
        
-       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
-                                        "Show Sliders|", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
-                                        ACTMENU_VIEW_SLIDERS, "");
-                                        
-       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOHIDE)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
-                                        "Show Hidden Channels|", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
-                                        ACTMENU_VIEW_NOHIDE, "");
-                                        
-       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NODRAWGCOLORS)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT, 
-                                        "Use Group Colors|", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
-                                        ACTMENU_VIEW_GCOLORS, "");
-                                        
-               // this option may get removed in future
-       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
-                                        "Cull Out-of-View Keys (Time)|", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
-                                        ACTMENU_VIEW_HORIZOPTIMISE, "");
+       if (G.saction->mode == SACTCONT_GPENCIL) {
+                       // this option may get removed in future
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
+                                                "Cull Out-of-View Keys (Time)|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_HORIZOPTIMISE, "");
+       }
+       else {
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
+                                                "Show Sliders|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_SLIDERS, "");
+                                                
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOHIDE)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
+                                                "Show Hidden Channels|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_NOHIDE, "");
+                                                
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NODRAWGCOLORS)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT, 
+                                                "Use Group Colors|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_GCOLORS, "");
+                                                
+                       // this option may get removed in future
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
+                                                "Cull Out-of-View Keys (Time)|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_HORIZOPTIMISE, "");
+               
+               uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOTRANSKEYCULL)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT, 
+                                                "AutoMerge Keyframes|", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                                ACTMENU_VIEW_TRANSDELDUPS, "");
+       }       
        
-       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOTRANSKEYCULL)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT, 
-                                        "AutoMerge Keyframes|", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
-                                        ACTMENU_VIEW_TRANSDELDUPS, "");
-                       
                
        uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
                                         "Lock Time to Other Windows|", 0, yco-=20, 
@@ -476,7 +499,7 @@ static uiBlock *action_viewmenu(void *arg_unused)
                                         menuwidth, 19, NULL, 0.0, 0.0, 1, 
                                         ACTMENU_VIEW_PREVRANGECLEAR, "");
                
-       if (G.saction->action) {
+       if ((G.saction->mode == SACTCONT_ACTION) && (G.saction->action)) {
                uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
                                         "Preview Range from Action Length|Ctrl Alt P", 0, yco-=20, 
                                         menuwidth, 19, NULL, 0.0, 0.0, 1, 
@@ -550,13 +573,15 @@ static uiBlock *action_selectmenu_columnmenu(void *arg_unused)
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
                                         "On Current Frame|Ctrl K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,  
                                         ACTMENU_SEL_COLUMN_CFRA, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "On Selected Markers|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_COLUMN_MARKERSCOLUMN, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Between Selected Markers|Alt K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_COLUMN_MARKERSBETWEEN, "");
        
+       if (G_SACTION_HASMARKERS) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "On Selected Markers|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_COLUMN_MARKERSCOLUMN, "");
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Between Selected Markers|Alt K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_COLUMN_MARKERSBETWEEN, "");
+       }
        
        uiBlockSetDirection(block, UI_RIGHT);
        uiTextBoundsBlock(block, 60);
@@ -659,14 +684,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
                                         "Border Select Keys|B", 0, yco-=20, 
                                         menuwidth, 19, NULL, 0.0, 0.0, 0, 
                                         ACTMENU_SEL_BORDER, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Border Select Channels|B", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_BORDERC, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Border Select Markers|Ctrl B", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_BORDERM, "");
+       if (G_SACTION_HASMARKERS) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Border Select Markers|Ctrl B", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_BORDERM, "");
+       }
+       if (G.saction->mode != SACTCONT_SHAPEKEY) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Border Select Channels|B", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_BORDERC, "");
+       }
                                         
        uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
                         menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -675,14 +704,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
                                         "Select/Deselect All Keys|A", 0, yco-=20, 
                                         menuwidth, 19, NULL, 0.0, 0.0, 0, 
                                         ACTMENU_SEL_ALL_KEYS, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Select/Deselect All Markers|Ctrl A", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_ALL_MARKERS, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Select/Deselect All Channels|A", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_ALL_CHAN, "");
+       if (G_SACTION_HASMARKERS) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Select/Deselect All Markers|Ctrl A", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_ALL_MARKERS, "");
+       }
+       if (G.saction->mode != SACTCONT_SHAPEKEY) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Select/Deselect All Channels|A", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_ALL_CHAN, "");
+       }
                                         
        uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
                         menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -691,14 +724,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
                                         "Inverse Keys|Ctrl I", 0, yco-=20, 
                                         menuwidth, 19, NULL, 0.0, 0.0, 0, 
                                         ACTMENU_SEL_INVERSE_KEYS, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Inverse Markers|Ctrl Shift I", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_INVERSE_MARKERS, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
-                                        "Inverse All Channels|Ctrl I", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 0, 
-                                        ACTMENU_SEL_INVERSE_CHANNELS, "");
+       if (G_SACTION_HASMARKERS) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Inverse Markers|Ctrl Shift I", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_INVERSE_MARKERS, "");
+       }
+       if (G.saction->mode != SACTCONT_SHAPEKEY) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                                "Inverse All Channels|Ctrl I", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                                ACTMENU_SEL_INVERSE_CHANNELS, "");
+       }
                
        uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
                         menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -971,6 +1008,40 @@ static uiBlock *action_channelmenu(void *arg_unused)
        return block;
 }
 
+/* note: uses do_action_channelmenu too... */
+static uiBlock *action_gplayermenu(void *arg_unused)
+{
+       uiBlock *block;
+       short yco= 0, menuwidth=120;
+
+       block= uiNewBlock(&curarea->uiblocks, "action_gplayermenu", 
+                                         UI_EMBOSSP, UI_HELV, curarea->headwin);
+       uiBlockSetButmFunc(block, do_action_channelmenu, NULL);
+       
+       uiDefIconTextBlockBut(block, action_channelmenu_settingsmenu, 
+                                                 NULL, ICON_RIGHTARROW_THIN, 
+                                                 "Settings", 0, yco-=20, 120, 20, ""); 
+       
+       uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
+                                       menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                       "Delete|X", 0, yco-=20,
+                       menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_CHANNELS_DELETE, "");
+       
+       if (curarea->headertype==HEADERTOP) {
+               uiBlockSetDirection(block, UI_DOWN);
+       }
+       else {
+               uiBlockSetDirection(block, UI_TOP);
+               uiBlockFlipOrder(block);
+       }
+
+       uiTextBoundsBlock(block, 50);
+
+       return block;
+}
+
 static void do_action_keymenu_transformmenu(void *arg, int event)
 {      
        switch (event)
@@ -1400,6 +1471,51 @@ static uiBlock *action_keymenu(void *arg_unused)
        return block;
 }
 
+/* note: uses do_action_keymenu too! */
+static uiBlock *action_framemenu(void *arg_unused)
+{
+       uiBlock *block;
+       short yco= 0, menuwidth=120;
+
+       block= uiNewBlock(&curarea->uiblocks, "action_framemenu", 
+                                         UI_EMBOSSP, UI_HELV, curarea->headwin);
+       uiBlockSetButmFunc(block, do_action_keymenu, NULL);
+       
+       uiDefIconTextBlockBut(block, action_keymenu_transformmenu, 
+                                                 NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 20, "");
+       
+       uiDefIconTextBlockBut(block, action_keymenu_snapmenu, 
+                                                 NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 20, "");
+       
+       uiDefIconTextBlockBut(block, action_keymenu_mirrormenu, 
+                                                 NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 20, "");
+       
+       uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
+                        menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+                                       
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                       "Duplicate|Shift D", 0, yco-=20, 
+                                       menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                       ACTMENU_KEY_DUPLICATE, "");
+       
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                       "Delete|X", 0, yco-=20, 
+                                       menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                       ACTMENU_KEY_DELETE, "");
+       
+       if(curarea->headertype==HEADERTOP) {
+               uiBlockSetDirection(block, UI_DOWN);
+       }
+       else {
+               uiBlockSetDirection(block, UI_TOP);
+               uiBlockFlipOrder(block);
+       }
+
+       uiTextBoundsBlock(block, 50);
+
+       return block;
+}
+
 static void do_action_markermenu(void *arg, int event)
 {      
        switch(event)
@@ -1461,17 +1577,19 @@ static uiBlock *action_markermenu(void *arg_unused)
                                         menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_NAME, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
                                         menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_MOVE, "");
-                                        
-       uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
-       
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Pose Marker|Shift L", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALADD, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Pose Marker|Ctrl Shift L", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALRENAME, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Pose Marker|Alt L", 0, yco-=20,
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALDELETE, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Pose Marker|Ctrl L", 0, yco-=20, 
-                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALMOVE, "");
+               
+       if (G.saction->mode == SACTCONT_ACTION) {
+               uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+               
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Pose Marker|Shift L", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALADD, "");
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Pose Marker|Ctrl Shift L", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALRENAME, "");
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Pose Marker|Alt L", 0, yco-=20,
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALDELETE, "");
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Pose Marker|Ctrl L", 0, yco-=20, 
+                                                menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALMOVE, "");
+       }
        
        if(curarea->headertype==HEADERTOP) {
                uiBlockSetDirection(block, UI_DOWN);
@@ -1498,6 +1616,7 @@ void action_buttons(void)
                return;
 
        /* copied from drawactionspace.... */
+       // FIXME: do for gpencil too?
        if (!G.saction->pin) {
                if (OBACT)
                        G.saction->action = OBACT->action;
@@ -1558,68 +1677,112 @@ void action_buttons(void)
                                          "Select", xco, -2, xmax-3, 24, "");
                xco+= xmax;
                
-               if (G.saction->action) {
+               if ((G.saction->action) && (G.saction->mode==SACTCONT_ACTION)) {
                        xmax= GetButStringLength("Channel");
                        uiDefPulldownBut(block, action_channelmenu, NULL, 
                                                  "Channel", xco, -2, xmax-3, 24, "");
                        xco+= xmax;
                }
+               else if ((G.saction->gpd) && (G.saction->mode==SACTCONT_GPENCIL)) {
+                       xmax= GetButStringLength("Channel");
+                       uiDefPulldownBut(block, action_gplayermenu, NULL, 
+                                                 "Channel", xco, -2, xmax-3, 24, "");
+                       xco+= xmax;
+               }
                
                xmax= GetButStringLength("Marker");
                uiDefPulldownBut(block, action_markermenu, NULL, 
                                          "Marker", xco, -2, xmax-3, 24, "");
                xco+= xmax;
                
-               xmax= GetButStringLength("Key");
-               uiDefPulldownBut(block, action_keymenu, NULL, 
-                                         "Key", xco, -2, xmax-3, 24, "");
-               xco+= xmax;
+               if (G.saction->mode == SACTCONT_GPENCIL) {
+                       xmax= GetButStringLength("Frame");
+                       uiDefPulldownBut(block, action_framemenu, NULL, 
+                                                 "Frame", xco, -2, xmax-3, 24, "");
+                       xco+= xmax;
+
+               }
+               else {
+                       xmax= GetButStringLength("Key");
+                       uiDefPulldownBut(block, action_keymenu, NULL, 
+                                                 "Key", xco, -2, xmax-3, 24, "");
+                       xco+= xmax;
+               }
        }
 
        uiBlockSetEmboss(block, UI_EMBOSS);
        
-       /* NAME ETC */
-       ob= OBACT;
-       from = (ID *)ob;
-
-       xco= std_libbuttons(block, xco, 0, B_ACTPIN, &G.saction->pin, 
-                                               B_ACTIONBROWSE, ID_AC, 0, (ID*)G.saction->action, 
-                                               from, &(G.saction->actnr), B_ACTALONE, 
-                                               B_ACTLOCAL, B_ACTIONDELETE, 0, B_KEEPDATA);     
+       /* MODE SELECTOR */
+       uiDefButC(block, MENU, B_REDR, 
+                       "Editor Mode %t|Action Editor %x0|ShapeKey Editor %x1|Grease Pencil %x2", 
+                       xco,0,90,YIC, &(G.saction->mode), 0, 1, 0, 0, 
+                       "Editing modes for this editor");
 
-       uiClearButLock();
-
-       xco += 8;
        
-       /* COPY PASTE */
-       uiBlockBeginAlign(block);
-       if (curarea->headertype==HEADERTOP) {
-               uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP,    xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
-               uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP,  xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
-       }
-       else {
-               uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN,  xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
-               uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN,        xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
-       }
-       uiBlockEndAlign(block);
-       xco += (XIC + 8);
+       xco += (90 + 8);
        
-       /* draw AUTOSNAP */
-       if (G.saction->flag & SACTION_DRAWTIME) {
-               uiDefButS(block, MENU, B_REDR,
-                               "Auto-Snap Keyframes %t|No Snap %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3", 
-                               xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0, 
-                               "Auto-snapping mode for keyframes when transforming");
+       /* MODE-DEPENDENT DRAWING */
+       if (G.saction->mode == SACTCONT_GPENCIL) {
+               char gp_name[64];
+               
+               /* pin button */
+               uiDefIconButS(block, ICONTOG, B_ACTPIN, ICON_PIN_DEHLT, xco,0,XIC,YIC, &G.saction->pin, 0, 0, 0, 0, "Keeps this view displaying the current data regardless of what Grease Pencil set is active");
+               xco += (XIC + 5);
+               
+               /* just a simple string to help identify if any content */
+               glRasterPos2f((float)xco, 5.0);
+               BIF_RasterPos((float)xco, 5.0); // stupid texture fonts
+               BIF_ThemeColor(TH_TEXT);
+               
+               sprintf(gp_name, (G.saction->gpd)?"Grease Pencil Data":"<None>");
+               xmax= GetButStringLength(gp_name);
+               BIF_DrawString(uiBlockGetCurFont(block), gp_name, (U.transopts & USER_TR_BUTTONS));
+               xco += xmax;
        }
        else {
-               uiDefButS(block, MENU, B_REDR, 
-                               "Auto-Snap Keyframes %t|No Snap %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3", 
-                               xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0, 
-                               "Auto-snapping mode for keyframes when transforming");
+               /* NAME ETC */
+               ob= OBACT;
+               from = (ID *)ob;
+               
+               xco= std_libbuttons(block, xco, 0, B_ACTPIN, &G.saction->pin, 
+                                                       B_ACTIONBROWSE, ID_AC, 0, (ID*)G.saction->action, 
+                                                       from, &(G.saction->actnr), B_ACTALONE, 
+                                                       B_ACTLOCAL, B_ACTIONDELETE, 0, B_KEEPDATA);     
+               
+               uiClearButLock();
+               
+               xco += 8;
+               
+               /* COPY PASTE */
+               uiBlockBeginAlign(block);
+               if (curarea->headertype==HEADERTOP) {
+                       uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP,    xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+                       uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP,  xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+               }
+               else {
+                       uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN,  xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+                       uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN,        xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+               }
+               uiBlockEndAlign(block);
+               xco += (XIC + 8);
+               
+               /* draw AUTOSNAP */
+               if (G.saction->flag & SACTION_DRAWTIME) {
+                       uiDefButC(block, MENU, B_REDR,
+                                       "Auto-Snap Keyframes %t|No Snap %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3", 
+                                       xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0, 
+                                       "Auto-snapping mode for keyframes when transforming");
+               }
+               else {
+                       uiDefButC(block, MENU, B_REDR, 
+                                       "Auto-Snap Keyframes %t|No Snap %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3", 
+                                       xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0, 
+                                       "Auto-snapping mode for keyframes when transforming");
+               }
+               
+               xco += (70 + 8);
        }
        
-       xco += (70 + 8);
-       
        /* draw LOCK */
        uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco, 0, XIC, YIC, 
                                  &(G.saction->lock), 0, 0, 0, 0, 
index ec6bbc9044cbabc665cc950794170e31452bc773..4c7b4aa80bc38056039bd746d3bb5a5057db9dd5 100644 (file)
@@ -110,12 +110,16 @@ static void do_node_viewmenu(void *arg, int event)
                case 3: /* View all */
                        snode_home(curarea, snode);
                        break;
+               case 4: /* Grease Pencil */
+                       add_blockhandler(curarea, NODES_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
+               break;
        }
        allqueue(REDRAWNODE, 0);
 }
 
 static uiBlock *node_viewmenu(void *arg_unused)
 {
+       SpaceNode *snode= curarea->spacedata.first; 
        uiBlock *block;
        short yco= 0, menuwidth=120;
        
@@ -123,6 +127,12 @@ static uiBlock *node_viewmenu(void *arg_unused)
                                          UI_EMBOSSP, UI_HELV, curarea->headwin);
        uiBlockSetButmFunc(block, do_node_viewmenu, NULL);
 
+       if (snode->nodetree) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Grease Pencil...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+               
+               uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       }
+       
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
        
index 393830a61cfce16ed8f708896a1397d597c14e98..e5a63b9fe458d8fbc42d458d96c4ece1d9598b65 100644 (file)
@@ -100,6 +100,9 @@ static void do_seq_viewmenu(void *arg, int event)
        case 6: /* Draw time/frames */
                sseq->flag ^= SEQ_DRAWFRAMES;
                break;
+       case 7: /* Grease Pencil */
+               add_blockhandler(curarea, SEQ_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
+               break;
        }
 }
 
@@ -111,7 +114,15 @@ static uiBlock *seq_viewmenu(void *arg_unused)
 
        block= uiNewBlock(&curarea->uiblocks, "seq_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
        uiBlockSetButmFunc(block, do_seq_viewmenu, NULL);
-
+       
+       if (sseq->mainb) {
+               uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, 
+                                "Grease Pencil...", 0, yco-=20,
+                                menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+                                
+               uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       }
+       
        if (sseq->mainb == 0) {
                uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
                                 "Play Back Animation "
index 0f3a46c8a8cbb77e0df2e580cf8f380327c4c8b9..71bf0cd9bd4a4b21f19aeaf78bb9728221043e0c 100644 (file)
@@ -601,6 +601,9 @@ static void do_view3d_viewmenu(void *arg, int event)
                break;
        case 20: /* Transform  Space Panel */
                add_blockhandler(curarea, VIEW3D_HANDLER_TRANSFORM, UI_PNL_UNSTOW);
+               break;  
+       case 21: /* Grease Pencil */
+               add_blockhandler(curarea, VIEW3D_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
                break;          
        }
        allqueue(REDRAWVIEW3D, 1);
@@ -619,6 +622,7 @@ static uiBlock *view3d_viewmenu(void *arg_unused)
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Render Preview...|Shift P",  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 18, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "View Properties...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 16, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Background Image...",        0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Grease Pencil...",   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 21, "");
        
        uiDefBut(block, SEPR, 0, "",                                    0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
        
index 19e2e4b62454dd430f3650abf31b47e0fbe7ee57..ba8649eaa8654eeff83075c032b33fc0dd5b35b8 100644 (file)
@@ -618,6 +618,9 @@ void uiBoundsBlock(uiBlock *block, int addval)
        uiBut *bt;
        int xof;
        
+       if(block==NULL)
+               return;
+       
        if(block->buttons.first==NULL) {
                if(block->panel) {
                        block->minx= 0.0; block->maxx= block->panel->sizex;
index 58420604c838169c7a44dd2a931193f603609695..92efb477095fe300202eafe4f6b3f0209e73c4a8 100644 (file)
@@ -56,6 +56,7 @@
 #include "DNA_armature_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_group_types.h" /* used for select_same_group */
+#include "DNA_gpencil_types.h"
 #include "DNA_image_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_mesh_types.h"
 #include "BDR_imagepaint.h"
 #include "BDR_sculptmode.h"
 #include "BDR_unwrapper.h"
+#include "BDR_gpencil.h"
 
 #include "BLO_readfile.h" /* for BLO_blendhandle_close */
 
@@ -1193,13 +1195,17 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                
                if(event==UI_BUT_EVENT) do_butspace(val); /* temporal, view3d deserves own queue? */
                
-               /* we consider manipulator a button, defaulting to leftmouse */
+               /* - we consider manipulator a button, defaulting to leftmouse 
+                * - grease-pencil also defaults to leftmouse
+                */
                if(event==LEFTMOUSE) {
                        /* run any view3d event handler script links */
-                       if (event && sa->scriptlink.totscript)
+                       if (event && sa->scriptlink.totscript) {
                                if (BPY_do_spacehandlers(sa, event, SPACEHANDLER_VIEW3D_EVENT))
                                        return; /* return if event was processed (swallowed) by handler(s) */
-
+                       }
+                       
+                       if(gpencil_do_paint(sa)) return;
                        if(BIF_do_manipulator(sa)) return;
                }
                
@@ -1207,7 +1213,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                if (U.flag & USER_LMOUSESELECT) {
                        /* only swap mouse button for selection, in modes where it is relevant.
                         * painting/sculpting stays on LEFTMOUSE */
-                       if (   !((G.f & G_SCULPTMODE) || (G.f & G_WEIGHTPAINT) ||
+                       if (   !((G.f & G_SCULPTMODE) || (G.f & G_WEIGHTPAINT) || (G.f & G_GREASEPENCIL) ||
                                (G.f & G_VERTEXPAINT) || (G.f & G_TEXTUREPAINT) || (G.f & G_PARTICLEEDIT)) ||
                                (G.obedit) )
                        {                       
@@ -1945,7 +1951,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                                adduplicate(0, 0);
                                }
                                else if(G.qual==LR_CTRLKEY) {
-                                       imagestodisplist();
+                                       imagestodisplist(); // removed
                                }
                                else if((G.qual==0)){
                                        pupval= pupmenu("Draw mode%t|BoundBox %x1|Wire %x2|OpenGL Solid %x3|Shaded Solid %x4|Textured Solid %x5");
@@ -4816,6 +4822,11 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        if(val) {
                if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
                
+               /* grease-pencil defaults to leftmouse */
+               if(event==LEFTMOUSE) {
+                       if(gpencil_do_paint(sa)) return;
+               }
+               
                /* swap mouse buttons based on user preference */
                if (U.flag & USER_LMOUSESELECT) {
                        if (event == LEFTMOUSE) {
@@ -4829,11 +4840,11 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                
                switch(event) {
                case LEFTMOUSE:
-                       if(sseq->mainb || view2dmove(event)==0) {
+                       if(sseq->mainb==0 && view2dmove(event)==0) {
                                
                                first= 1;               
                                set_special_seq_update(1);
-
+                               
                                do {
                                        getmouseco_areawin(mval);
                                        areamouseco_to_ipoco(v2d, mval, &dx, &dy);
@@ -6241,6 +6252,7 @@ void freespacelist(ScrArea *sa)
                                if(vd->bgpic->ima) vd->bgpic->ima->id.us--;
                                MEM_freeN(vd->bgpic);
                        }
+                       if(vd->gpd) free_gpencil_data(vd->gpd);
                        if(vd->localvd) MEM_freeN(vd->localvd);
                        if(vd->clipbb) MEM_freeN(vd->clipbb);
                        if(vd->depths) {
@@ -6284,7 +6296,12 @@ void freespacelist(ScrArea *sa)
                                curvemapping_free(sima->cumap);
                }
                else if(sl->spacetype==SPACE_NODE) {
-/*                     SpaceNode *snode= (SpaceNode *)sl; */
+                       SpaceNode *snode= (SpaceNode *)sl;
+                       if(snode->gpd) free_gpencil_data(snode->gpd);
+               }
+               else if(sl->spacetype==SPACE_SEQ) {
+                       SpaceSeq *sseq= (SpaceSeq *)sl;
+                       if(sseq->gpd) free_gpencil_data(sseq->gpd);
                }
        }
 
@@ -6314,6 +6331,7 @@ void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
                        BIF_view3d_previewrender_free(v3d);
                        v3d->depths= NULL;
                        v3d->retopo_view_data= NULL;
+                       v3d->gpd= gpencil_data_duplicate(v3d->gpd);
                }
                else if(sl->spacetype==SPACE_OOPS) {
                        SpaceOops *so= (SpaceOops *)sl;
@@ -6333,11 +6351,16 @@ void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
                else if(sl->spacetype==SPACE_NODE) {
                        SpaceNode *snode= (SpaceNode *)sl;
                        snode->nodetree= NULL;
+                       snode->gpd= gpencil_data_duplicate(snode->gpd);
                }
                else if(sl->spacetype==SPACE_SCRIPT) {
                        SpaceScript *sc = ( SpaceScript * ) sl;
                        sc->but_refs = NULL;
                }
+               else if(sl->spacetype==SPACE_SEQ) {
+                       SpaceSeq *sseq= (SpaceSeq *)sl;
+                       sseq->gpd= gpencil_data_duplicate(sseq->gpd);
+               }
                sl= sl->next;
        }
        
index 562d9a4934d9c6e0530fbec4cf5d77c525d433a6..706b079432cfb000b2e7ca178de36d3db1a8e1b8 100644 (file)
@@ -70,6 +70,7 @@
 #include "DNA_vfont_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
 
 #include "BKE_action.h"
 #include "BKE_armature.h"
 
 #include "BDR_drawaction.h"            // list of keyframes in action
 #include "BDR_editobject.h"            // reset_slowparents()
+#include "BDR_gpencil.h"
 #include "BDR_unwrapper.h"
 
 #include "BLI_arithb.h"
@@ -2474,6 +2476,96 @@ void flushTransIpoData(TransInfo *t)
 
 /* ********************* ACTION/NLA EDITOR ****************** */
 
+/* Called by special_aftertrans_update to make sure selected gp-frames replace
+ * any other gp-frames which may reside on that frame (that are not selected).
+ * It also makes sure gp-frames are still stored in chronological order after
+ * transform.
+ */
+static void posttrans_gpd_clean (bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       
+       for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+               ListBase sel_buffer = {NULL, NULL};
+               bGPDframe *gpf, *gpfn;
+               bGPDframe *gfs, *gfsn;
+               
+               /* loop 1: loop through and isolate selected gp-frames to buffer 
+                * (these need to be sorted as they are isolated)
+                */
+               for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+                       gpfn= gpf->next;
+                       
+                       if (gpf->flag & GP_FRAME_SELECT) {
+                               BLI_remlink(&gpl->frames, gpf);
+                               
+                               /* find place to add them in buffer
+                                * - go backwards as most frames will still be in order,
+                                *   so doing it this way will be faster 
+                                */
+                               for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) {
+                                       /* if current (gpf) occurs after this one in buffer, add! */
+                                       if (gfs->framenum < gpf->framenum) {
+                                               BLI_insertlinkafter(&sel_buffer, gfs, gpf);
+                                               break;
+                                       }
+                               }
+                               if (gfs == NULL)
+                                       BLI_addhead(&sel_buffer, gpf);
+                       }
+               }
+               
+               /* error checking: it is unlikely, but may be possible to have none selected */
+               if (sel_buffer.first == NULL)
+                       continue;
+               
+               /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */
+               if (gpl->frames.first == NULL) {
+                       gpl->frames.first= sel_buffer.first;
+                       gpl->frames.last= sel_buffer.last;
+                       
+                       continue;
+               }
+               
+               /* loop 2: remove duplicates of frames in buffers */
+               //gfs= sel_buffer.first;
+               //gfsn= gfs->next;
+               
+               for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) {
+                       gpfn= gpf->next;
+                        
+                       /* loop through sel_buffer, emptying stuff from front of buffer if ok */
+                       for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) {
+                               gfsn= gfs->next;
+                               
+                               /* if this buffer frame needs to go before current, add it! */
+                               if (gfs->framenum < gpf->framenum) {
+                                       /* transfer buffer frame to frames list (before current) */
+                                       BLI_remlink(&sel_buffer, gfs);
+                                       BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
+                               }
+                               /* if this buffer frame is on same frame, replace current with it and stop */
+                               else if (gfs->framenum == gpf->framenum) {
+                                       /* transfer buffer frame to frames list (before current) */
+                                       BLI_remlink(&sel_buffer, gfs);
+                                       BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
+                                       
+                                       /* get rid of current frame */
+                                       gpencil_layer_delframe(gpl, gpf);
+                               }
+                       }
+               }
+               
+               /* if anything is still in buffer, append to end */
+               for (gfs= sel_buffer.first; gfs; gfs= gfsn) {
+                       gfsn= gfs->next;
+                       
+                       BLI_remlink(&sel_buffer, gfs);
+                       BLI_addtail(&gpl->frames, gfs);
+               }
+       }
+}
+
 /* Called by special_aftertrans_update to make sure selected keyframes replace
  * any other keyframes which may reside on that frame (that is not selected).
  */
@@ -2698,6 +2790,26 @@ static int count_ipo_keys(Ipo *ipo, char side, float cfra)
        return count;
 }
 
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+{
+       bGPDframe *gpf;
+       int count = 0;
+       
+       if (gpl == NULL)
+               return count;
+       
+       /* only include points that occur on the right side of cfra */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if (gpf->flag & GP_FRAME_SELECT) {
+                       if (FrameOnMouseSide(side, gpf->framenum, cfra))
+                               count++;
+               }
+       }
+       
+       return count;
+}
+
 /* This function assigns the information to transdata */
 static void TimeToTransData(TransData *td, float *time, Object *ob)
 {
@@ -2751,9 +2863,68 @@ static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side,
        return td;
 }
 
+/* helper struct for gp-frame transforms (only used here) */
+typedef struct tGPFtransdata {
+       float val;                      /* where transdata writes transform */
+       int *sdata;                     /* pointer to gpf->framenum */
+} tGPFtransdata;
+
+/* This function helps flush transdata written to tempdata into the gp-frames  */
+void flushTransGPactionData (TransInfo *t)
+{
+       tGPFtransdata *tfd;
+       int i;
+       
+       /* find the first one to start from */
+       if (t->mode == TFM_TIME_SLIDE)
+               tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
+       else
+               tfd= (tGPFtransdata *)(t->customData);
+               
+       /* flush data! */
+       for (i = 0; i < t->total; i++, tfd++) {
+               *(tfd->sdata)= (int)floor(tfd->val + 0.5);
+       }       
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones...  i.e.   td = GPLayerToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used. 
+ */
+static int GPLayerToTransData (TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, short side, float cfra)
+{
+       bGPDframe *gpf;
+       int count= 0;
+       
+       /* check for select frames on right side of current frame */
+       for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+               if (gpf->flag & GP_FRAME_SELECT) {
+                       if (FrameOnMouseSide(side, gpf->framenum, cfra)) {
+                               /* memory is calloc'ed, so that should zero everything nicely for us */
+                               td->val= &tfd->val;
+                               td->ival= gpf->framenum;
+                               
+                               tfd->val= gpf->framenum;
+                               tfd->sdata= &gpf->framenum;
+                               
+                               /* advance td now */
+                               td++;
+                               tfd++;
+                               count++;
+                       }
+               }
+       }
+       
+       return count;
+}
+
 static void createTransActionData(TransInfo *t)
 {
        TransData *td = NULL;
+       tGPFtransdata *tfd = NULL;
        Object *ob= NULL;
        
        ListBase act_data = {NULL, NULL};
@@ -2771,7 +2942,10 @@ static void createTransActionData(TransInfo *t)
        if (data == NULL) return;
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       if (datatype == ACTCONT_GPENCIL)
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+       else
+               filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* is the action scaled? if so, the it should belong to the active object */
@@ -2800,8 +2974,12 @@ static void createTransActionData(TransInfo *t)
                cfra = CFRA;
        
        /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
-       for (ale= act_data.first; ale; ale= ale->next)
-               count += count_ipo_keys(ale->key_data, side, cfra);
+       for (ale= act_data.first; ale; ale= ale->next) {
+               if (ale->type == ACTTYPE_GPLAYER)
+                       count += count_gplayer_frames(ale->data, side, cfra);
+               else
+                       count += count_ipo_keys(ale->key_data, side, cfra);
+       }
        
        /* stop if trying to build list if nothing selected */
        if (count == 0) {
@@ -2812,16 +2990,38 @@ static void createTransActionData(TransInfo *t)
        
        /* allocate memory for data */
        t->total= count;
+       
        t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
-       if (t->mode == TFM_TIME_SLIDE)
+       td= t->data;
+       
+       if (datatype == ACTCONT_GPENCIL) {
+               if (t->mode == TFM_TIME_SLIDE) {
+                       t->customData= MEM_callocN((sizeof(float)*2)+(sizeof(tGPFtransdata)*count), "TimeSlide + tGPFtransdata");
+                       tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
+               }
+               else {
+                       t->customData= MEM_callocN(sizeof(tGPFtransdata)*count, "tGPFtransdata");
+                       tfd= (tGPFtransdata *)(t->customData);
+               }
+       }
+       else if (t->mode == TFM_TIME_SLIDE)
                t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
        
-       td= t->data;
        /* loop 2: build transdata array */
        for (ale= act_data.first; ale; ale= ale->next) {
-               Ipo *ipo= (Ipo *)ale->key_data;
-               
-               td= IpoToTransData(td, ipo, ob, side, cfra);
+               if (ale->type == ACTTYPE_GPLAYER) {
+                       bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                       int i;
+                       
+                       i = GPLayerToTransData(td, tfd, gpl, side, cfra);
+                       td += i;
+                       tfd += i;
+               }
+               else {
+                       Ipo *ipo= (Ipo *)ale->key_data;
+                       
+                       td= IpoToTransData(td, ipo, ob, side, cfra);
+               }
        }
        
        /* check if we're supposed to be setting minx/maxx for TimeSlide */
@@ -3673,6 +3873,13 @@ void special_aftertrans_update(TransInfo *t)
                        
                        DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
                }
+               else if (datatype == ACTCONT_GPENCIL) {
+                       /* remove duplicate frames and also make sure points are in order! */
+                       if ((cancelled == 0) || (duplicate))
+                       {
+                               posttrans_gpd_clean(data);
+                       }
+               }
                
                G.saction->flag &= ~SACTION_MOVING;
        }
index 6cb7a34d1bc9626c6f483467e7dfbfc863a45e8e..c332fd723ebd7b499d66b00fbaecd81d9e2c8f30 100644 (file)
@@ -278,6 +278,11 @@ void recalcData(TransInfo *t)
                data = get_action_context(&context);
                if (data == NULL) return;
                
+               /* always flush data if gpencil context */
+               if (context == ACTCONT_GPENCIL) {
+                       flushTransGPactionData(t);
+               }
+               
                if (G.saction->lock) {
                        if (context == ACTCONT_ACTION) {
                                if(ob) {
@@ -753,6 +758,10 @@ void postTrans (TransInfo *t)
                if (G.sima->flag & SI_LIVE_UNWRAP)
                        unwrap_lscm_live_end(t->state == TRANS_CANCEL);
        }
+       else if(t->spacetype==SPACE_ACTION) {
+               if (t->customData)
+                       MEM_freeN(t->customData);
+       }
 }
 
 void applyTransObjects(TransInfo *t)
index c7b2a671f78b7e9dae03c191ed5ec7b2d3d28bb9..539eaec4a7b17fb2eba88f6c07af1fda3884bad1 100644 (file)
@@ -135,7 +135,7 @@ void        KX_BulletPhysicsController::getOrientation(MT_Quaternion& orn)
 }
 void KX_BulletPhysicsController::setOrientation(const MT_Matrix3x3& orn)
 {
-       btMatrix3x3 btmat(orn[0][0], orn[0][1], orn[1][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]);
+       btMatrix3x3 btmat(orn[0][0], orn[0][1], orn[0][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]);
        CcdPhysicsController::setWorldOrientation(btmat);
 }
 void KX_BulletPhysicsController::setPosition(const MT_Point3& pos)