svn merge -r 15590:15688 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorAndre Susano Pinto <andresusanopinto@gmail.com>
Tue, 22 Jul 2008 12:02:57 +0000 (12:02 +0000)
committerAndre Susano Pinto <andresusanopinto@gmail.com>
Tue, 22 Jul 2008 12:02:57 +0000 (12:02 +0000)
98 files changed:
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/intern/collision.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenlib/intern/arithb.c
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/python/api2_2x/Blender.c
source/blender/python/api2_2x/Library.c
source/blender/python/api2_2x/Particle.c
source/blender/python/api2_2x/doc/LibData.py
source/blender/python/api2_2x/doc/Particle.py
source/blender/python/api2_2x/doc/Render.py
source/blender/python/api2_2x/sceneRender.c
source/blender/render/intern/source/rendercore.c
source/blender/render/intern/source/shadeoutput.c
source/blender/src/drawaction.c
source/blender/src/drawgpencil.c [new file with mode: 0644]
source/blender/src/drawnode.c
source/blender/src/drawobject.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/editmesh.c
source/blender/src/editnode.c
source/blender/src/editobject.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/blender/src/usiblender.c
source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/BL_DeformableGameObject.h
source/gameengine/Converter/BL_ShapeDeformer.cpp
source/gameengine/Converter/BL_SkinDeformer.cpp
source/gameengine/Converter/BL_SkinDeformer.h
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/GameLogic/SCA_ILogicBrick.cpp
source/gameengine/GameLogic/SCA_ILogicBrick.h
source/gameengine/GameLogic/SCA_IObject.cpp
source/gameengine/GameLogic/SCA_PropertyActuator.cpp
source/gameengine/GameLogic/SCA_PropertyActuator.h
source/gameengine/GamePlayer/common/GPC_Canvas.h
source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
source/gameengine/Ketsji/KX_BulletPhysicsController.h
source/gameengine/Ketsji/KX_CameraActuator.cpp
source/gameengine/Ketsji/KX_CameraActuator.h
source/gameengine/Ketsji/KX_ConstraintActuator.cpp
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_IPhysicsController.h
source/gameengine/Ketsji/KX_OdePhysicsController.cpp
source/gameengine/Ketsji/KX_OdePhysicsController.h
source/gameengine/Ketsji/KX_ParentActuator.cpp
source/gameengine/Ketsji/KX_ParentActuator.h
source/gameengine/Ketsji/KX_RadarSensor.cpp
source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/Ketsji/KX_SceneActuator.cpp
source/gameengine/Ketsji/KX_SceneActuator.h
source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
source/gameengine/Ketsji/KX_SumoPhysicsController.h
source/gameengine/Ketsji/KX_TrackToActuator.cpp
source/gameengine/Ketsji/KX_TrackToActuator.h
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
source/gameengine/PyDoc/KX_GameObject.py
source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
source/gameengine/Rasterizer/RAS_2DFilterManager.h
source/gameengine/Rasterizer/RAS_ICanvas.h
source/gameengine/SceneGraph/SG_IObject.cpp
source/gameengine/SceneGraph/SG_IObject.h
source/gameengine/SceneGraph/SG_Node.cpp
source/gameengine/SceneGraph/SG_Node.h

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 26c5d186d8703b995d22aca66ccd1ede9d293ece..6dfb77504fb3d7cf6babdf2104fc0dd07fc620f0 100644 (file)
@@ -1437,6 +1437,9 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj)
 
                                        if(coll_ob == self)
                                                continue;
+                                       
+                                       if( !collmd->bvhtree)
+                                               continue;
 
                                        if(numobj >= maxobj)
                                        {
index e8bcae42d5a97764732e1a237d345427747cd5f1..54915058bab7b21778a8c29ff0a3db9d86e04ab2 100644 (file)
@@ -915,7 +915,10 @@ void lattice_calc_modifiers(Object *ob)
                mti->deformVerts(md, ob, NULL, vertexCos, numVerts);
        }
 
-       if (vertexCos) {
+       /* always displist to make this work like derivedmesh */
+       if (!vertexCos) vertexCos = lattice_getVertexCos(ob, &numVerts);
+       
+       {
                DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
                dl->type = DL_VERTS;
                dl->parts = 1;
index f70648965f413a5b9474f12cc2ae1150f1ee8c90..7dca87d5c135ad53b2de60acda7a7af89b365e44 100644 (file)
@@ -2797,7 +2797,10 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
                                epart= epsys->part;
                                pd= epart->pd;
                                totepart= epsys->totpart;
-
+                               
+                               if(totepart <= 0)
+                                       continue;
+                               
                                if(pd->forcefield==PFIELD_HARMONIC){
                                        /* every particle is mapped to only one harmonic effector particle */
                                        p= pa_no%epsys->totpart;
index dd9c76d91727381c9edd86bff3365bbc28341925..a31c769a5b34f1978491b3846963a82c204cc5b2 100644 (file)
@@ -59,6 +59,7 @@
 
 /* A few small defines. Keep'em local! */
 #define SMALL_NUMBER   1.e-8
+#define CLAMP(a, b, c)         if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
 
 
 #if defined(WIN32) || defined(__APPLE__)
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 d8385c1d6609d61f75783b04cb1aa5d809f9ad98..420d292cdcef7073eec1c18f12e0ad6ba2eda759 100644 (file)
@@ -708,7 +708,7 @@ static PyObject *Blender_Save( PyObject * self, PyObject * args )
                                              "expected filename and optional int (overwrite flag) as arguments" );
 
        for( li = G.main->library.first; li; li = li->id.next ) {
-               if( BLI_streq( li->name, fname ) ) {
+               if( li->parent==NULL && BLI_streq( li->name, fname ) ) {
                        return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                                      "cannot overwrite used library" );
                }
index 799735c2062fc31aebe2b57bd4d4f8f0140df1d0..468263c420817d107099d5631b9120f0b2ce795b 100644 (file)
@@ -1135,9 +1135,78 @@ static PyObject *M_Library_Load(PyObject *self, PyObject * args)
        return (PyObject *)lib;
 }
 
+static PyObject *M_Library_GetPaths(PyObject *self, PyObject * args)
+{      
+       PyObject *list;
+       PyObject *name;
+       int type=0;
+       Library *lib;
+       
+       if( !PyArg_ParseTuple( args, "|i", &type ) || type < 0 || type > 2 ) {
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                       "expected an int between 0 and 2." );
+       }
+       
+       list = PyList_New(0);
+       
+       for(lib= G.main->library.first; lib; lib= lib->id.next) {
+               if (type==0) {
+                       /* any type is ok */
+               } else if (type==1 && lib->parent == 0) {
+                       /* only direct linked */
+               } else if (type==2 && lib->parent != 0) {
+                       /* only indirect */
+               } else {
+                       continue; /* incompatible type */
+               }
+               
+               name = PyString_FromString(lib->name);
+               PyList_Append(list, name);
+               Py_DECREF(name);
+       }
+       return list;
+}
+
+static PyObject *M_Library_ReplacePath(PyObject *self, PyObject * args)
+{
+       char *name_from, *name_to;
+       Library *lib;
+       
+       if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to )) {
+               return EXPP_ReturnPyObjError( PyExc_TypeError,
+                       "expected the name of a library path" );
+       }
+       
+       for(lib= G.main->library.first; lib; lib= lib->id.next) {
+               if (strcmp(lib->name, name_from)==0) {
+                       if (lib->parent) {
+                               return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+                                       "path is indirectly linked, cannot be changed." );
+                       }
+                       
+                       if (strlen(name_to) > sizeof(lib->name)) {
+                               return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+                                       "string length too long, cannot set path." );
+                       }
+                       
+                       strcpy(lib->name, name_to);
+                       Py_RETURN_NONE;
+               }
+       }
+       
+       return EXPP_ReturnPyObjError( PyExc_ValueError,
+               "path given does not exist as a library" );
+}
+
+
+
 static struct PyMethodDef M_Library_methods[] = {
        {"load", (PyCFunction)M_Library_Load, METH_VARARGS,
        "(string) - declare a .blend file for use as a library"},
+       {"paths", (PyCFunction)M_Library_GetPaths, METH_VARARGS,
+       "(type) - return a list of library paths, type 0 for all, 1 only direct links, 2 only indirect links"},
+       {"replace", (PyCFunction)M_Library_ReplacePath, METH_VARARGS,
+       "(from, to) - replace the path of an existing, directly linked library."},
        {NULL, NULL, 0, NULL}
 };
 
index 95de9757b8709c3f81ea686535841ddcf480ff07..2c2e724129ed7a63b048e6d4e78c6a297a5eaaa9 100644 (file)
@@ -40,6 +40,7 @@
 #include "BKE_material.h"
 #include "BKE_utildefines.h"
 #include "BKE_pointcache.h"
+#include "BKE_DerivedMesh.h"
 #include "BIF_editparticle.h"
 #include "BIF_space.h"
 #include "blendef.h"
@@ -799,22 +800,27 @@ static PyObject *Part_freeEdit( BPy_PartSys * self, PyObject * args ){
        Py_RETURN_NONE;
 }
 
-static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){
+static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args )
+{
        ParticleSystem *psys = 0L;
        Object *ob = 0L;
        PyObject *partlist,*seglist;
-       PyObject* loc = 0L;
        ParticleCacheKey **cache,*path;
+       PyObject* loc = 0L;
        ParticleKey state;
-       float cfra=bsystem_time(ob,(float)CFRA,0.0);
+       DerivedMesh* dm;
+       float cfra;
        int i,j,k;
+       float vm[4][4],wm[4][4];
        int     childexists = 0;
        int all = 0;
        int id = 0;
 
+       cfra = bsystem_time(ob,(float)CFRA,0.0);
+
        if( !PyArg_ParseTuple( args, "|ii", &all,&id ) )
                return EXPP_ReturnPyObjError( PyExc_TypeError,
-                               "expected one optional integer as argument" );
+                               "expected two optional integers as arguments" );
 
        psys = self->psys;
        ob = self->object;
@@ -822,88 +828,118 @@ static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){
        if (!ob || !psys)
                Py_RETURN_NONE;
 
-       if (psys->part->type == 2){
-               cache=psys->pathcache;
+       G.rendering = 1;
 
-               /* little hack to calculate hair steps in render mode */
-               psys->renderdata = (void*)(int)1;
+       /* Just to create a valid rendering context */
+       psys_render_set(ob,psys,vm,wm,0,0,0);
 
-               psys_cache_paths(ob, psys, cfra, 1);
+       dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+       dm->release(dm);
 
-               psys->renderdata = NULL;
+       if ( !psys_check_enabled(ob,psys) ){
+               G.rendering = 0;
+               psys_render_restore(ob,psys);
+               Particle_Recalc(self,1);
+               Py_RETURN_NONE;
+       }
 
-               partlist = PyList_New( 0 );
-               if( !partlist )
-                       return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" );
+       partlist = PyList_New( 0 );
+       if( !partlist ){
+               PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" );
+               goto error;
+       }
 
-               for(i = 0; i < psys->totpart; i++){
-                       path=cache[i];
-                       seglist = PyList_New( 0 );
-                       k = path->steps+1;
-                       for( j = 0; j < k ; j++){
-                               loc = PyTuple_New(3);
-
-                               PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)path->co[0]));
-                               PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)path->co[1]));
-                               PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)path->co[2]));
-
-                               if ( (PyList_Append(seglist,loc) < 0) ){
-                                       Py_DECREF(seglist);
-                                       Py_DECREF(partlist);
-                                       Py_XDECREF(loc);
-                                       return EXPP_ReturnPyObjError( PyExc_RuntimeError,
-                                                       "Couldn't append item to PyList" );
+       if (psys->part->type == PART_HAIR){
+               cache = psys->pathcache;
+
+               if ( ((self->psys->part->draw & PART_DRAW_PARENT) && (self->psys->part->childtype != 0)) || (self->psys->part->childtype == 0) ){
+
+                       for(i = 0; i < psys->totpart; i++){
+                               seglist = PyList_New( 0 );
+                               if (!seglist){
+                                       PyErr_SetString( PyExc_MemoryError,
+                                                       "PyList_New() failed" );
+                                       goto error;
+                               }
+
+                               path=cache[i];
+                               k = path->steps+1;
+                               for( j = 0; j < k ; j++, path++){
+                                       loc = Py_BuildValue("(fff)",(double)path->co[0],
+                                                       (double)path->co[1], (double)path->co[2]);
+
+                                       if (!loc){
+                                               PyErr_SetString( PyExc_RuntimeError,
+                                                               "Couldn't build tuple" );
+                                               goto error;
+                                       }
+
+                                       if ( (PyList_Append(seglist,loc) < 0) ){
+                                               PyErr_SetString( PyExc_RuntimeError,
+                                                               "Couldn't append item to PyList" );
+                                               goto error;
+                                       }
+                                       Py_DECREF(loc); /* PyList_Append increfs */
+                                       loc = NULL;
                                }
-                               Py_DECREF(loc); /* PyList_Append increfs */
-                               path++;
-                       }
 
-                       if ( PyList_Append(partlist,seglist) < 0 ){
-                               Py_DECREF(seglist);
-                               Py_DECREF(partlist);
-                               return EXPP_ReturnPyObjError( PyExc_RuntimeError,
-                                               "Couldn't append item to PyList" );             
+                               if ( PyList_Append(partlist,seglist) < 0 ){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't append item to PyList" );             
+                                       goto error;
+                               }
+                               Py_DECREF(seglist); /* PyList_Append increfs */
+                               seglist = NULL;
                        }
-                       Py_DECREF(seglist); /* PyList_Append increfs */
                }
 
                cache=psys->childcache;
 
                for(i = 0; i < psys->totchild; i++){
-                       path=cache[i];
                        seglist = PyList_New( 0 );
-                       k = path->steps+1;
-                       for( j = 0; j < k ; j++){
-                               loc = PyTuple_New(3);
+                       if (!seglist){
+                               PyErr_SetString( PyExc_MemoryError,
+                                               "PyList_New() failed" );
+                               goto error;
+                       }
 
-                               PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)path->co[0]));
-                               PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)path->co[1]));
-                               PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)path->co[2]));
+                       path=cache[i];
+                       k = path->steps+1;
+                       for( j = 0; j < k ; j++, path++ ){
+                               loc = Py_BuildValue("(fff)",(double)path->co[0],
+                                               (double)path->co[1], (double)path->co[2]);
+
+                               if (!loc){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't build tuple" );
+                                       goto error;
+                               }
 
                                if ( PyList_Append(seglist,loc) < 0){
-                                       Py_DECREF(partlist);
-                                       Py_XDECREF(loc);
-                                       return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+                                       PyErr_SetString( PyExc_RuntimeError,
                                                        "Couldn't append item to PyList" );
+                                       goto error;
                                }
                                Py_DECREF(loc);/* PyList_Append increfs */
-                               path++;
+                               loc = NULL;
                        }
 
                        if ( PyList_Append(partlist,seglist) < 0){
-                               Py_DECREF(partlist);
-                               Py_XDECREF(loc);
-                               return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+                               PyErr_SetString( PyExc_RuntimeError,
                                                "Couldn't append item to PyList" );     
+                               goto error;
                        }
                        Py_DECREF(seglist); /* PyList_Append increfs */
+                       seglist = NULL;
                }
-               
        } else {
                int init;
-               partlist = PyList_New( 0 );
-               if( !partlist )
-                       return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" );
+               char *fmt = NULL;
+
+               if(id)
+                       fmt = "(fffi)";
+               else
+                       fmt = "(fff)";
 
                if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
                        childexists = 1;
@@ -919,55 +955,67 @@ static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){
                                init = 1;
 
                        if (init){
-                               if (!id)
-                                       loc = PyTuple_New(3);
-                               else
-                                       loc = PyTuple_New(4);
-                               PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)state.co[0]));
-                               PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)state.co[1]));
-                               PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)state.co[2]));
-                               if (id)
-                                       PyTuple_SetItem(loc,3,PyInt_FromLong(i));
+                               loc = Py_BuildValue(fmt,(double)state.co[0],
+                                               (double)state.co[1], (double)state.co[2],i);
+                               
+                               if (!loc){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't build tuple" );
+                                       goto error;
+                               }
 
                                if ( PyList_Append(partlist,loc) < 0 ){
-                                       Py_DECREF(partlist);
-                                       Py_XDECREF(loc);
-                                       return EXPP_ReturnPyObjError( PyExc_RuntimeError,
-                                                               "Couldn't append item to PyList" );
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't append item to PyList" );
+                                       goto error;
                                }
-                               Py_DECREF(loc);/* PyList_Append increfs */
-                       }
-                       else {
-                               if ( all ){
-                                       if ( PyList_Append(partlist,Py_None) < 0 ){
-                                               Py_DECREF(partlist);
-                                               return EXPP_ReturnPyObjError( PyExc_RuntimeError,
-                                                                       "Couldn't append item to PyList" );
-                                       }
-                                       Py_DECREF(Py_None); /* PyList_Append increfs */
+                               Py_DECREF(loc);
+                               loc = NULL;
+                       } else {
+                               if ( all && PyList_Append(partlist,Py_None) < 0 ){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't append item to PyList" );
+                                       goto error;
                                }
                        }
                }
        }
+
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
        return partlist;
+
+error:
+       Py_XDECREF(partlist);
+       Py_XDECREF(seglist);
+       Py_XDECREF(loc);
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
+       return NULL;
 }
 
-static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args ){
+static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args )
+{
        ParticleSystem *psys = 0L;
        Object *ob = 0L;
        PyObject *partlist = 0L;
        PyObject* loc = 0L;
        ParticleKey state;
+       DerivedMesh* dm;
+       float vm[4][4],wm[4][4];
        int i;
        int childexists = 0;
        int all = 0;
        int id = 0;
+    char *fmt = NULL;
 
        float cfra=bsystem_time(ob,(float)CFRA,0.0);
 
        if( !PyArg_ParseTuple( args, "|ii", &all, &id ) )
                return EXPP_ReturnPyObjError( PyExc_TypeError,
-                               "expected one optional integer as argument" );
+                               "expected two optional integers as arguments" );
 
        psys = self->psys;
        ob = self->object;
@@ -975,63 +1023,105 @@ static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args ){
        if (!ob || !psys)
                Py_RETURN_NONE;
 
-       if (psys->part->type != 2){
+       G.rendering = 1;
+
+       /* Just to create a valid rendering context */
+       psys_render_set(ob,psys,vm,wm,0,0,0);
+
+       dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+       dm->release(dm);
+
+       if ( !psys_check_enabled(ob,psys) ){
+               G.rendering = 0;
+               psys_render_restore(ob,psys);
+               Particle_Recalc(self,1);
+               Py_RETURN_NONE;
+       }
+
+       if (psys->part->type != PART_HAIR){
                partlist = PyList_New( 0 );
 
+               if( !partlist ){
+                       PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" );
+                       goto error;
+               }
+
                if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
                        childexists = 1;
 
+               if(id)
+                       fmt = "(ffffi)";
+               else
+                       fmt = "(ffff)";
+
                for (i = 0; i < psys->totpart + psys->totchild; i++){
                        if (childexists && (i < psys->totpart))
                                continue;
 
                        state.time = cfra;
                        if(psys_get_particle_state(ob,psys,i,&state,0)==0){
-                               if ( all ){
-                                       PyList_Append(partlist,Py_None);
-                                       Py_DECREF(Py_None); /* PyList_Append increfs */
-                                       continue;
-                               } else {
-                                       continue;
+                               if ( all && PyList_Append(partlist,Py_None) < 0){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                               "Couldn't append item to PyList" );
+                                       goto error;
+                               }
+                       } else {
+                               loc = Py_BuildValue(fmt,(double)state.rot[0], (double)state.rot[1],
+                                               (double)state.rot[2], (double)state.rot[3], i);
+
+                               if (!loc){
+                                       PyErr_SetString( PyExc_RuntimeError,
+                                                       "Couldn't build tuple" );
+                                       goto error;
+                               }
+                               if (PyList_Append(partlist,loc) < 0){
+                                       PyErr_SetString ( PyExc_RuntimeError,
+                                                       "Couldn't append item to PyList" );
+                                       goto error;
                                }
+                               Py_DECREF(loc); /* PyList_Append increfs */
+                               loc = NULL;
                        }
-                       if (!id)
-                               loc = PyTuple_New(4);
-                       else
-                               loc = PyTuple_New(5);
-                       PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)state.rot[0]));
-                       PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)state.rot[1]));
-                       PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)state.rot[2]));
-                       PyTuple_SetItem(loc,3,PyFloat_FromDouble((double)state.rot[3]));
-                       if (id)
-                               PyTuple_SetItem(loc,4,PyInt_FromLong(i));
-                       PyList_Append(partlist,loc);
-                       Py_DECREF(loc); /* PyList_Append increfs */
                }
+       } else {
+               partlist = EXPP_incr_ret( Py_None );
        }
+
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
        return partlist;
+
+error:
+       Py_XDECREF(partlist);
+       Py_XDECREF(loc);
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
+       return NULL;
 }
 
-static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){
+static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args )
+{
        ParticleKey state;
        ParticleSystem *psys = 0L;
        ParticleData *data;
        Object *ob = 0L;
        PyObject *partlist,*tuple;
-       PyObject* siz = 0L;
+       DerivedMesh* dm;
+       float vm[4][4],wm[4][4];
        float size;
        int i;
        int childexists = 0;
        int all = 0;
        int id = 0;
+    char *fmt = NULL;
 
        float cfra=bsystem_time(ob,(float)CFRA,0.0);
 
        if( !PyArg_ParseTuple( args, "|ii", &all, &id ) )
                return EXPP_ReturnPyObjError( PyExc_TypeError,
-                               "expected one optional integer as argument" );
-
-       data = self->psys->particles;
+                               "expected two optional integers as arguments" );
 
        psys = self->psys;
        ob = self->object;
@@ -1039,13 +1129,39 @@ static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){
        if (!ob || !psys)
                Py_RETURN_NONE;
 
-               partlist = PyList_New( 0 );
+       G.rendering = 1;
 
-               if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
-                       childexists = 1;
+       /* Just to create a valid rendering context */
+       psys_render_set(ob,psys,vm,wm,0,0,0);
+
+       dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+       dm->release(dm);
+       data = self->psys->particles;
+
+       if ( !psys_check_enabled(ob,psys) ){
+               psys_render_restore(ob,psys);
+               G.rendering = 0;
+               Particle_Recalc(self,1);
+               Py_RETURN_NONE;
+       }
+
+       partlist = PyList_New( 0 );
+
+       if( !partlist ){
+               PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" );
+               goto error;
+       }
+
+       if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
+               childexists = 1;
+
+       if(id)
+               fmt = "(fi)";
+       else
+               fmt = "f";
 
-               for (i = 0; i < psys->totpart + psys->totchild; i++, data++){
-               if (psys->part->type != 2){
+       for (i = 0; i < psys->totpart + psys->totchild; i++, data++){
+               if (psys->part->type != PART_HAIR){
                        if (childexists && (i < psys->totpart))
                                continue;
 
@@ -1061,43 +1177,61 @@ static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){
                                ChildParticle *cpa= &psys->child[i-psys->totpart];
                                size = psys_get_child_size(psys,cpa,cfra,0);
                        }
-                       if (id){
-                               tuple = PyTuple_New(2);
-                               PyTuple_SetItem(tuple,0,PyFloat_FromDouble((double)size));
-                               PyTuple_SetItem(tuple,1,PyInt_FromLong(i));
-                               PyList_Append(partlist,tuple);
-                               Py_DECREF(tuple);
-                       } else {
-                               siz = PyFloat_FromDouble((double)size);
-                               PyList_Append(partlist,siz);
-                               Py_DECREF(siz);
+
+                       tuple = Py_BuildValue(fmt,(double)size,i);
+
+                       if (!tuple){
+                               PyErr_SetString( PyExc_RuntimeError,
+                                               "Couldn't build tuple" );
+                               goto error;
+                       }
+
+                       if (PyList_Append(partlist,tuple) < 0){
+                               PyErr_SetString( PyExc_RuntimeError,
+                                               "Couldn't append item to PyList" );
+                               goto error;
                        }
+                       Py_DECREF(tuple);
+                       tuple = NULL;
                }
        }
+
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
        return partlist;
+
+error:
+       Py_XDECREF(partlist);
+       Py_XDECREF(tuple);
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
+       return NULL;
 }
 
 
-static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){
+static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args )
+{
        ParticleKey state;
        ParticleSystem *psys = 0L;
        ParticleData *data;
        Object *ob = 0L;
        PyObject *partlist,*tuple;
-       PyObject* lif = 0L;
+       DerivedMesh* dm;
+       float vm[4][4],wm[4][4];
        float life;
        int i;
        int childexists = 0;
        int all = 0;
        int id = 0;
+       char *fmt = NULL;
 
        float cfra=bsystem_time(ob,(float)CFRA,0.0);
 
        if( !PyArg_ParseTuple( args, "|ii", &all, &id ) )
                return EXPP_ReturnPyObjError( PyExc_TypeError,
-                               "expected one optional integer as argument" );
-
-       data = self->psys->particles;
+                               "expected two optional integers as arguments" );
 
        psys = self->psys;
        ob = self->object;
@@ -1105,13 +1239,37 @@ static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){
        if (!ob || !psys)
                Py_RETURN_NONE;
 
-               partlist = PyList_New( 0 );
+       G.rendering = 1;
 
-               if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
-                       childexists = 1;
+       /* Just to create a valid rendering context */
+       psys_render_set(ob,psys,vm,wm,0,0,0);
+
+       dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+       dm->release(dm);
+       data = self->psys->particles;
+
+       if ( !psys_check_enabled(ob,psys) ){
+               psys_render_restore(ob,psys);
+               G.rendering = 0;
+               Py_RETURN_NONE;
+       }
+
+       partlist = PyList_New( 0 );
+       if( !partlist ){
+               PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" );
+               goto error;
+       }
+
+       if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
+               childexists = 1;
+
+       if(id)
+               fmt = "(fi)";
+       else
+               fmt = "f";
 
-               for (i = 0; i < psys->totpart + psys->totchild; i++, data++){
-               if (psys->part->type != 2){
+       for (i = 0; i < psys->totpart + psys->totchild; i++, data++){
+               if (psys->part->type != PART_HAIR){
 
                        if (childexists && (i < psys->totpart))
                                continue;
@@ -1128,20 +1286,37 @@ static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){
                                ChildParticle *cpa= &psys->child[i-psys->totpart];
                                life = psys_get_child_time(psys,cpa,cfra);
                        }
-                       if (id){
-                               tuple = PyTuple_New(2);
-                               PyTuple_SetItem(tuple,0,PyFloat_FromDouble((double)life));
-                               PyTuple_SetItem(tuple,1,PyInt_FromLong(i));
-                               PyList_Append(partlist,tuple);
-                               Py_DECREF(tuple);
-                       } else {
-                               lif = PyFloat_FromDouble((double)life);
-                               PyList_Append(partlist,lif);
-                               Py_DECREF(lif);
+
+                       tuple = Py_BuildValue(fmt,(double)life,i);
+
+                       if (!tuple){
+                               PyErr_SetString( PyExc_RuntimeError,
+                                               "Couldn't build tuple" );
+                               goto error;
                        }
+
+                       if (PyList_Append(partlist,tuple) < 0){
+                               PyErr_SetString( PyExc_RuntimeError,
+                                               "Couldn't append item to PyList" );
+                               goto error;
+                       }
+                       Py_DECREF(tuple);
+                       tuple = NULL;
                }
        }
+
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
        return partlist;
+
+error:
+       Py_XDECREF(partlist);
+       Py_XDECREF(tuple);
+       psys_render_restore(ob,psys);
+       G.rendering = 0;
+       Particle_Recalc(self,1);
+       return NULL;
 }
 
 
@@ -1376,11 +1551,8 @@ static int Part_set2d( BPy_PartSys * self, PyObject * args )
 {
        int number;
 
-       if( !PyInt_Check( args ) ) {
-               char errstr[128];
-               sprintf ( errstr, "expected int argument" );
-               return EXPP_ReturnIntError( PyExc_TypeError, errstr );
-       }
+       if( !PyInt_Check( args ) )
+               return EXPP_ReturnIntError( PyExc_TypeError, "expected int argument" );
 
        number = PyInt_AS_LONG( args );
 
@@ -1526,7 +1698,7 @@ static int Part_setRandEmission( BPy_PartSys * self, PyObject * args )
 
 static PyObject *Part_getRandEmission( BPy_PartSys * self )
 {
-       return PyInt_FromLong( ((long)( self->psys->part->flag & PART_BOIDS_2D )) > 0 );
+       return PyInt_FromLong( ((long)( self->psys->part->flag & PART_TRAND )) > 0 );
 }
 
 static int Part_setParticleDist( BPy_PartSys * self, PyObject * args )
@@ -1546,7 +1718,7 @@ static int Part_setParticleDist( BPy_PartSys * self, PyObject * args )
                return EXPP_ReturnIntError( PyExc_TypeError, errstr );
        }
 
-       self->psys->part->from = number;
+       self->psys->part->from = (short)number;
 
        Particle_RecalcPsys_distr(self,1);
 
@@ -1603,7 +1775,7 @@ static int Part_setDist( BPy_PartSys * self, PyObject * args )
                return EXPP_ReturnIntError( PyExc_TypeError, errstr );
        }
 
-       self->psys->part->distr = number;
+       self->psys->part->distr = (short)number;
 
        Particle_RecalcPsys_distr(self,1);
 
@@ -1731,7 +1903,7 @@ static int Part_setTargetPsys( BPy_PartSys * self, PyObject * args ){
 
        res = EXPP_setIValueRange( args, &self->psys->target_psys, 0, tottpsys, 'h' );
 
-       if((psys=psys_get_current(ob))){
+       if( ( psys = psys_get_current(ob) ) ){
                if(psys->keyed_ob==ob || psys->target_ob==ob){
                        if(psys->keyed_ob==ob)
                                psys->keyed_ob=NULL;
index 47bd7fdb763efafd334438c4eea7bfe24f2efff2..daa6a186531958a3e555b90671efe661bdc7034c 100644 (file)
@@ -27,17 +27,37 @@ Example::
 """
 
 def load(filename,relative=False):
-  """
-  Select an existing .blend file for use as a library.  Unlike the 
-  Library module, multiple libraries can be defined at the same time.  
-  
-  @type filename: string
-  @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location.
-  @type relative: boolean
-  @param relative: Convert relative paths to absolute paths (default).  Setting this parameter to True will leave paths relative.
-  @rtype: Library
-  @return: return a L{Library} object.
-  """
+       """
+       Select an existing .blend file for use as a library.  Unlike the 
+       Library module, multiple libraries can be defined at the same time.  
+       
+       @type filename: string
+       @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location.
+       @type relative: boolean
+       @param relative: Convert relative paths to absolute paths (default).  Setting this parameter to True will leave paths relative.
+       @rtype: Library
+       @return: return a L{Library} object.
+       """
+
+def paths(link=0):
+       """
+       Returns a list of paths used in the current blend file.
+       
+       @type link: int
+       @param link: 0 (default if no args given) for all library paths, 1 for directly linked library paths only, 2 for indirectly linked library paths only.
+       @rtype: List
+       @return: return a list of path strings.
+       """
+
+def replace(pathFrom, pathTo):
+       """
+       Replaces an existing directly linked path.
+       
+       @type pathFrom: string
+       @param pathFrom: An existing library path.
+       @type pathTo: string
+       @param pathTo: A new library path.
+       """
 
 class Libraries:
        """
index 192ecd5355b3a92383239d16e8a0efdd7b00b28e..511ad81b45f0ccc5fe51ed305e6ca2f084e25f60 100644 (file)
@@ -56,17 +56,17 @@ class Particle:
        @type type: int
        @ivar resolutionGrid: The resolution of the particle grid.
        @type resolutionGrid: int
-       @ivar startFrame: Frame # to start emitting particles.
+       @ivar startFrame: Frame number to start emitting particles.
        @type startFrame: float
-       @ivar endFrame: Frame # to stop emitting particles.
+       @ivar endFrame: Frame number to stop emitting particles.
        @type endFrame: float
        @ivar editable: Finalize hair to enable editing in particle mode.
        @type editable: int
        @ivar amount: The total number of particles.
        @type amount: int
-       @ivar multireact: React multiple times ( Paricle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ).
+       @ivar multireact: React multiple times ( Particle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ).
        @type multireact: int
-       @ivar reactshape: Power of reaction strength dependence on distance to target.
+       @ivar reactshape: Power of reaction strength, dependent on distance to target.
        @type reactshape: float
        @ivar hairSegments: Amount of hair segments.
        @type hairSegments: int
@@ -74,13 +74,13 @@ class Particle:
        @type lifetime: float
        @ivar randlife: Give the particle life a random variation.
        @type randlife: float
-       @ivar randemission: Give the particle life a random variation
+       @ivar randemission: Emit particles in random order.
        @type randemission: int
-       @ivar particleDistribution: Where to emit particles from  Paricle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] )
+       @ivar particleDistribution: Where to emit particles from  ( Particle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] )
        @type particleDistribution: int
        @ivar evenDistribution: Use even distribution from faces based on face areas or edge lengths.
        @type evenDistribution: int
-       @ivar distribution: How to distribute particles on selected element Paricle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ).
+       @ivar distribution: How to distribute particles on selected element ( Particle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ).
        @type distribution: int
        @ivar jitterAmount: Amount of jitter applied to the sampling.
        @type jitterAmount: float
@@ -131,237 +131,56 @@ class Particle:
                Get the particles locations.
                A list of tuple is returned in particle mode.
                A list of list of tuple is returned in hair mode.
-               The tuple is a vector list of 3 or 4 floats in world space (x,y,z, optionnaly the particle's id).
+               The tuple is a vector of 3 or 4 floats in world space (x,y,z,
+optionally the particle's id).
                @type all: int
                @param all: if not 0 export all particles (uninitialized (unborn or died)particles exported as None).
                @type id: int
                @param id: add the particle id in the end of the vector tuple
-               @rtype: list of vectors (tuple of 3 floats and optionnaly the id) or list of list of vectors
-               @return: list of vectors or list of list of vectors (hair mode)
+               @rtype: list of vectors (tuple of 3 floats and optionally the id) or list of list of vectors
+               @return: list of vectors or list of list of vectors (hair mode) or None if system is disabled
                """
        def getRot(all=0,id=0):
                """
-               Get the particles rotations as quaternion.
+               Get the particles' rotations as quaternion.
                A list of tuple is returned in particle mode.
-               The tuple is a vector list of 4 or 5 floats (x,y,z,w, optionnaly the id of the particle).
+               The tuple is vector of 4 or 5 floats (x,y,z,w, optionally the id of the particle).
                
                @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None).
+               @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None).
                @type id: int
                @param id: add the particle id in the return tuple
                @rtype: list of tuple of 4 or 5 elements (if id is not zero)
-               @return: list of 4-tuples
+               @return: list of 4-tuples or None if system is disabled
                """
                
        def getMat():
                """
-               Get the particles material.
+               Get the particles' material.
                @rtype: Blender Material
-               @return: The marterial assigned to particles
+               @return: The material assigned to particles
                """
                
        def getSize(all=0,id=0):
                """
-               Get the particles size.
+               Get the particles' size.
                A list of float or list of tuple (particle's size,particle's id).
                @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None).
+               @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None).
                @type id: int
                @param id: add the particle id in the return tuple
                @rtype: list of floats
-               @return: list of floats or list of tuples if id is not zero (size,id).
+               @return: list of floats or list of tuples if id is not zero (size,id) or None if system is disabled.
                """
                
        def getAge(all=0,id=0):
                """
-               Get the particles age.
-               A list of float or list of tuple (particle's age,particle's id).
+               Get the particles' age.
+               A list of float or list of tuple (particle's age, particle's id).
                @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None).
+               @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None).
                @type id: int
                @param id: add the particle id in the return tuple
                @rtype: list of floats
-               @return: list of floats or list of tuples if id is not zero (size,id).
-               """
-# Blender.Object module and the Object PyType object
-
-"""
-The Blender.Particle submodule
-
-
-Particle
-========
-
-This module provides access to the B{Particle} in Blender.
-
-@type TYPE: readonly dictionary
-@var TYPE: Constant dict used for with L{Particle.TYPE}
-               - HAIR: set particle system to hair mode.
-               - REACTOR: set particle system to reactor mode.
-               - EMITTER: set particle system to emitter mode.
-@type DISTRIBUTION: readonly dictionary
-@var DISTRIBUTION: Constant dict used for with L{Particle.DISTRIBUTION}
-               - GRID: set grid distribution.
-               - RANDOM: set random distribution.
-               - JITTERED: set jittered distribution.
-@type EMITFROM: readonly dictionary
-@var EMITFROM: Constant dict used for with L{Particle.EMITFROM}
-               - VERTS: set particles emit from vertices
-               - FACES: set particles emit from faces
-               - VOLUME: set particles emit from volume
-               - PARTICLE: set particles emit from particles
-@type REACTON: readonly dictionary
-@var REACTON: Constant dict used for with L{Particle.REACTON}
-               - NEAR: react on near
-               - COLLISION: react on collision
-               - DEATH: react on death
-@type DRAWAS: readonly dictionary
-@var DRAWAS: Constant dict used for with L{Particle.DRAWAS}
-               - NONE: Don't draw
-               - POINT: Draw as point
-               - CIRCLE: Draw as circles
-               - CROSS: Draw as crosses
-               - AXIS: Draw as axis
-               - LINE: Draw as lines
-               - PATH: Draw pathes
-               - OBJECT: Draw object
-               - GROUP: Draw goup
-               - BILLBOARD: Draw as billboard 
-"""
-
-def Get(name):
-               """
-               Get the particle system of the object "name".
-               @type name: string
-               @return: The particle system of the object.
-               """
-def New(name):
-               """
-               Assign a new particle system to the object "name".
-               @type name: string
-               @return: The newly created particle system.
-               """
-
-class Particle:
-       """
-       The Particle object
-       ===================
-               This object gives access to paticles data.
-               
-       @ivar seed: Set an offset in the random table.
-       @type seed: int
-       @ivar type: Type of particle system ( Particle.TYPE[ 'HAIR' | 'REACTOR' | 'EMITTER' ] ).
-       @type type: int
-       @ivar resolutionGrid: The resolution of the particle grid.
-       @type resolutionGrid: int
-       @ivar startFrame: Frame # to start emitting particles.
-       @type startFrame: float
-       @ivar endFrame: Frame # to stop emitting particles.
-       @type endFrame: float
-       @ivar editable: Finalize hair to enable editing in particle mode.
-       @type editable: int
-       @ivar amount: The total number of particles.
-       @type amount: int
-       @ivar multireact: React multiple times ( Paricle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ).
-       @type multireact: int
-       @ivar reactshape: Power of reaction strength dependence on distance to target.
-       @type reactshape: float
-       @ivar hairSegments: Amount of hair segments.
-       @type hairSegments: int
-       @ivar lifetime: Specify the life span of the particles.
-       @type lifetime: float
-       @ivar randlife: Give the particle life a random variation.
-       @type randlife: float
-       @ivar randemission: Give the particle life a random variation
-       @type randemission: int
-       @ivar particleDistribution: Where to emit particles from  Paricle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] )
-       @type particleDistribution: int
-       @ivar evenDistribution: Use even distribution from faces based on face areas or edge lengths.
-       @type evenDistribution: int
-       @ivar distribution: How to distribute particles on selected element Paricle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ).
-       @type distribution: int
-       @ivar jitterAmount: Amount of jitter applied to the sampling.
-       @type jitterAmount: float
-       @ivar pf: Emission locations / face (0 = automatic).
-       @type pf:int
-       @ivar invert: Invert what is considered object and what is not.
-       @type invert: int
-       @ivar targetObject: The object that has the target particle system (empty if same object).
-       @type targetObject: Blender object
-       @ivar targetpsys: The target particle system number in the object.
-       @type targetpsys: int
-       @ivar 2d: Constrain boids to a surface.
-       @type 2d: float
-       @ivar maxvel: Maximum velocity.
-       @type maxvel: float
-       @ivar avvel: The usual speed % of max velocity.
-       @type avvel: float
-       @ivar latacc: Lateral acceleration % of max velocity
-       @type latacc: float
-       @ivar tanacc: Tangential acceleration % of max velocity
-       @type tanacc: float
-       @ivar groundz: Default Z value.
-       @type groundz: float
-       @ivar object: Constrain boids to object's surface.
-       @type object: Blender Object
-       @ivar renderEmitter: Render emitter object.
-       @type renderEmitter: int
-       @ivar displayPercentage: Particle display percentage.
-       @type displayPercentage: int
-       @ivar hairDisplayStep: How many steps paths are drawn with (power of 2) in visu mode.
-       @type hairDisplayStep: int
-       @ivar hairRenderStep: How many steps paths are rendered with (power of 2) in render mode."
-       @type hairRenderStep: int
-       @ivar duplicateObject: Get the duplicate object.
-       @type duplicateObject: Blender Object
-       @ivar drawAs: Get draw type Particle.DRAWAS([ 'NONE' | 'OBJECT' | 'POINT' | ... ]).
-       @type drawAs: int
-       """
-       def freeEdit():
-               """
-               Free edit mode.
-               @return: None
-               """
-
-       def getLoc(all=0,id=0):
-               """
-               Get the particles locations.
-               A list of tuple is returned in particle mode.
-               A list of list of tuple is returned in hair mode.
-               The tuple is a vector list of 3 floats in world space.
-               @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died)particles exported as None).
-               @type id: int
-               @param id: add the particle id in the end of the vector tuple
-               @rtype: list of vectors (tuple of 3 floats and optionnaly the id) or list of list of vectors
-               @return: list of vectors or list of list of vectors (hair mode)
-               """
-       def getRot(all=0,id=0):
-               """
-               Get the particles rotations as quaternion.
-               A list of tuple is returned in particle mode.
-               The tuple is a vector list of 4 floats (quaternion).
-               @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None).
-               @type id: int
-               @param id: add the particle id in the return tuple
-               @rtype: list of tuple of 4 or 5 elements (if id is not zero)
-               @return: list of 4-tuples
-               """
-       def getMat():
-               """
-               Get the particles material.
-               @rtype: Blender Material
-               @return: The marterial assigned to particles
-               """
-       def getSize(all=0,id=0):
-               """
-               Get the particles size.
-               A list of float.
-               @type all: int
-               @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None).
-               @type id: int
-               @param id: add the particle id in the return tuple
-               @rtype: list of floats
-               @return: list of floats or list of tuples if id is not zero (size,id).
+               @return: list of floats or list of tuples if id is not zero (size,id) or None if system is disabled.
                """
index 475a4fc5b10c902cbf5dc9078d0b9c3b7dff98f8..d4dc83e84a039491b9c8e9c24e8b07b4eaf83893 100644 (file)
@@ -833,9 +833,7 @@ class RenderData:
 
   def enableCropping(toggle):
     """
-    Enable/disable exclusion of border rendering from total image.
-    @type toggle: int
-    @param toggle: pass 1 for on / 0 for off
+    Deprecated: see the L{crop} attribute.
     """
 
   def setImageType(type):
index b446af7efd401bf21a59c7c7caccd0609a62ee09..d382d4509703321dd5ce1e039c57c09dd1671224 100644 (file)
@@ -985,7 +985,7 @@ PyObject *RenderData_EnableCropping( void )
 /*     return M_Render_BitToggleInt( args, R_MOVIECROP,
                                      &self->renderContext->mode );
 */
-       printf("cropping option is now default, obsolete\n");
+       printf("obsolete: movie cropping option is now default\n");
        Py_RETURN_NONE;
 }
 
index 67be0ce4c005f62ff24583887429bd85cf1c3fb8..4520e4c10bb3f6f42b9f6fb5cfddc8e483342062 100644 (file)
@@ -671,8 +671,10 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
        RenderPass *zpass;
        GroupObject *go;
        LampRen *lar;
-       
-       int x, y;
+       RenderLayer *rlpp[RE_MAX_OSA];
+
+       int totsample, fullsample, sample;
+       int x, y,od;
        short first_lamp;
        float *zrect;
        float *rgbrect;
@@ -683,7 +685,10 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
        
        fac = 0.5;
        facm = 1.0 - fac;
-       
+
+       totsample= get_sample_layers(pa, rl, rlpp);
+       fullsample= (totsample > 1);
+
        /* check that z pass is enabled */
        if(pa->rectz==NULL) return;
        for(zpass= rl->passes.first; zpass; zpass= zpass->next)
@@ -708,9 +713,10 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
        
        zrect = zpass->rect;
        rgbrect = rl->rectf;
+       od=0;
        /* for each x,y and sun lamp*/
        for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
-               for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, zrect++, rgbrect+=4) {
+               for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, zrect++, od++) {
                        
                        first_lamp = 1;
                        for(go=R.lights.first; go; go= go->next) {
@@ -724,7 +730,7 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
                                        }
 
                                        if(lar->sunsky->effect_type & LA_SUN_EFFECT_AP){        
-                                               VECCOPY(tmp_rgb, rgbrect);
+                                               VECCOPY(tmp_rgb, (float*)(rgbrect+4*od));
 
                                                shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect);
                                                
@@ -743,7 +749,16 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
 
                        /* if at least for one sun lamp aerial perspective was applied*/
                        if(first_lamp==0)
-                               VECCOPY(rgbrect, rgb);
+                       {
+                               if(fullsample) {
+                                       for(sample=0; sample<totsample; sample++) {
+                                               VECCOPY((float*)(rlpp[sample]->rectf + od*4), rgb);
+                                       }
+                               }
+                               else {
+                                       VECCOPY((float*)(rgbrect+4*od), rgb);
+                               }
+                       }
                }
        }
 }
index 0928042729a5c65a26cf3fb467e3246e43fbb567..5b69323667edce2188c09b7045d5431f0c430a8b 100644 (file)
@@ -1379,6 +1379,8 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                }
                
                /* specularity */
+               shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
+               
                if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
                        
                        if(!(passflag & (SCE_PASS_COMBINED|SCE_PASS_SPEC)));
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 045bf292446225718cd1e6bad03250c3d716d32c..1a469e8b3660b29e2e6b22008a13e6f6efb94ebb 100644 (file)
@@ -1199,7 +1199,12 @@ static void drawlattice(Object *ob)
        int use_wcol= 0;
 
        lt= (ob==G.obedit)?editLatt:ob->data;
+       
+       /* now we default make displist, this will modifiers work for non animated case */
+       if(ob->disp.first==NULL)
+               lattice_calc_modifiers(ob);
        dl= find_displist(&ob->disp, DL_VERTS);
+       
        if(ob==G.obedit) {
                cpack(0x004000);
                
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 9eef61e11f95805cbc8edf71ed6076df5fa64447..188f7476728885880e74d2560a46c268aff63765 100644 (file)
@@ -340,8 +340,9 @@ void free_editface(EditFace *efa)
 #endif
        EM_remove_selection(efa, EDITFACE);
        
-       if (G.editMesh->act_face==efa)
-               EM_set_actFace(NULL);
+       if (G.editMesh->act_face==efa) {
+               EM_set_actFace( G.editMesh->faces.first == efa ? NULL : G.editMesh->faces.first);
+       }
                
        CustomData_em_free_block(&G.editMesh->fdata, &efa->data);
        if(efa->fast==0)
@@ -1059,7 +1060,11 @@ void make_editMesh()
        EM_hide_reset();
        /* sets helper flags which arent saved */
        EM_fgon_flags();
-
+       
+       if (EM_get_actFace(0)==NULL) {
+               EM_set_actFace( G.editMesh->faces.first ); /* will use the first face, this is so we alwats have an active face */
+       }
+               
        /* vertex coordinates change with cache edit, need to recalc */
        if(cacheedit)
                recalc_editnormals();
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);
                        }
index 2e5785eaab89b88f1d8cd8d79328c6909e6b5dda..6af4f47ed11cdbc91e0a55b4087716014eec7444 100644 (file)
@@ -5505,6 +5505,7 @@ void selectlinks(int nr)
                allqueue(REDRAWDATASELECT, 0);
                allqueue(REDRAWOOPS, 0);
                BIF_undo_push("Select linked");
+               countall();
        }
 }
 
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;
+       }
+