Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_global.h2
-rw-r--r--source/blender/blenkernel/intern/collision.c3
-rw-r--r--source/blender/blenkernel/intern/lattice.c5
-rw-r--r--source/blender/blenkernel/intern/particle_system.c5
-rw-r--r--source/blender/blenlib/intern/arithb.c252
-rw-r--r--source/blender/blenlib/intern/storage.c1
-rw-r--r--source/blender/blenloader/intern/readfile.c64
-rw-r--r--source/blender/blenloader/intern/writefile.c34
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp2
-rw-r--r--source/blender/include/BDR_drawaction.h3
-rw-r--r--source/blender/include/BDR_gpencil.h76
-rw-r--r--source/blender/include/BIF_drawgpencil.h44
-rw-r--r--source/blender/include/BIF_editaction.h30
-rw-r--r--source/blender/include/BIF_resources.h3
-rw-r--r--source/blender/include/BIF_space.h8
-rw-r--r--source/blender/include/BSE_editaction_types.h6
-rw-r--r--source/blender/include/blendef.h6
-rw-r--r--source/blender/include/transform.h1
-rw-r--r--source/blender/makesdna/DNA_action_types.h20
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h4
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h141
-rw-r--r--source/blender/makesdna/DNA_space_types.h8
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h15
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/python/api2_2x/Blender.c2
-rw-r--r--source/blender/python/api2_2x/Library.c69
-rw-r--r--source/blender/python/api2_2x/Particle.c472
-rw-r--r--source/blender/python/api2_2x/doc/Ipo.py4
-rw-r--r--source/blender/python/api2_2x/doc/LibData.py42
-rw-r--r--source/blender/python/api2_2x/doc/Particle.py229
-rw-r--r--source/blender/python/api2_2x/doc/Render.py4
-rw-r--r--source/blender/python/api2_2x/sceneRender.c2
-rw-r--r--source/blender/render/intern/source/rendercore.c27
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2
-rw-r--r--source/blender/render/intern/source/zbuf.c24
-rw-r--r--source/blender/src/buttons_editing.c54
-rw-r--r--source/blender/src/buttons_logic.c16
-rw-r--r--source/blender/src/buttons_scene.c72
-rw-r--r--source/blender/src/drawaction.c231
-rw-r--r--source/blender/src/drawgpencil.c653
-rw-r--r--source/blender/src/drawnode.c77
-rw-r--r--source/blender/src/drawobject.c5
-rw-r--r--source/blender/src/drawseq.c97
-rw-r--r--source/blender/src/drawview.c80
-rw-r--r--source/blender/src/editaction.c504
-rw-r--r--source/blender/src/editaction_gpencil.c549
-rw-r--r--source/blender/src/editmesh.c11
-rw-r--r--source/blender/src/editnode.c37
-rw-r--r--source/blender/src/editobject.c1
-rw-r--r--source/blender/src/editsound.c2
-rw-r--r--source/blender/src/gpencil.c1290
-rw-r--r--source/blender/src/header_action.c377
-rw-r--r--source/blender/src/header_node.c10
-rw-r--r--source/blender/src/header_seq.c13
-rw-r--r--source/blender/src/header_view3d.c4
-rw-r--r--source/blender/src/interface.c7
-rw-r--r--source/blender/src/poselib.c18
-rw-r--r--source/blender/src/resources.c28
-rw-r--r--source/blender/src/space.c43
-rw-r--r--source/blender/src/transform_conversions.c225
-rw-r--r--source/blender/src/transform_generics.c9
-rw-r--r--source/blender/src/usiblender.c2
63 files changed, 5119 insertions, 909 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 62289d227c7..8c9634cba06 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -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
+
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 26c5d186d87..6dfb77504fb 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1437,6 +1437,9 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj)
if(coll_ob == self)
continue;
+
+ if( !collmd->bvhtree)
+ continue;
if(numobj >= maxobj)
{
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index e8bcae42d5a..54915058bab 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -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;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index f70648965f4..7dca87d5c13 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -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;
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index c97ca3c6a8a..b7598ec0c4d 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -60,6 +60,7 @@
#define SMALL_NUMBER 1.e-8
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
#if defined(WIN32) || defined(__APPLE__)
@@ -3800,12 +3801,50 @@ int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], flo
/* Adapted from the paper by Kasper Fauerby */
/* "Improved Collision detection and Response" */
+static int getLowestRoot(float a, float b, float c, float maxR, float* root)
+{
+ // Check if a solution exists
+ float determinant = b*b - 4.0f*a*c;
+
+ // If determinant is negative it means no solutions.
+ if (determinant >= 0.0f)
+ {
+ // calculate the two roots: (if determinant == 0 then
+ // x1==x2 but let’s disregard that slight optimization)
+ float sqrtD = sqrt(determinant);
+ float r1 = (-b - sqrtD) / (2.0f*a);
+ float r2 = (-b + sqrtD) / (2.0f*a);
+
+ // Sort so x1 <= x2
+ if (r1 > r2)
+ SWAP( float, r1, r2);
+
+ // Get lowest root:
+ if (r1 > 0.0f && r1 < maxR)
+ {
+ *root = r1;
+ return 1;
+ }
+
+ // It is possible that we want x2 - this can happen
+ // if x1 < 0
+ if (r2 > 0.0f && r2 < maxR)
+ {
+ *root = r2;
+ return 1;
+ }
+ }
+ // No (valid) solutions
+ return 0;
+}
+
int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint)
{
float e1[3], e2[3], e3[3], point[3], vel[3], /*dist[3],*/ nor[3], temp[3], bv[3];
- float a, b, c, d, e, x, y, z, t, t0, t1, radius2=radius*radius;
+ float a, b, c, d, e, x, y, z, radius2=radius*radius;
float elen2,edotv,edotbv,nordotv,vel2;
- int embedded_in_plane=0, found_by_sweep=0;
+ float newLambda;
+ int found_by_sweep=0;
VecSubf(e1,v1,v0);
VecSubf(e2,v2,v0);
@@ -3814,44 +3853,41 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
/*---test plane of tri---*/
Crossf(nor,e1,e2);
Normalize(nor);
+
/* flip normal */
if(Inpf(nor,vel)>0.0f) VecMulf(nor,-1.0f);
a=Inpf(p1,nor)-Inpf(v0,nor);
-
nordotv=Inpf(nor,vel);
- if ((nordotv > -0.000001) && (nordotv < 0.000001)) {
- if(fabs(a)>=1.0f)
+ if (fabs(nordotv) < 0.000001)
+ {
+ if(fabs(a)>=radius)
+ {
return 0;
- else{
- embedded_in_plane=1;
- t0=0.0f;
- t1=1.0f;
}
}
- else{
- t0=(radius-a)/nordotv;
- t1=(-radius-a)/nordotv;
- /* make t0<t1 */
- if(t0>t1){b=t1; t1=t0; t0=b;}
+ else
+ {
+ float t0=(-a+radius)/nordotv;
+ float t1=(-a-radius)/nordotv;
+
+ if(t0>t1)
+ SWAP(float, t0, t1);
if(t0>1.0f || t1<0.0f) return 0;
/* clamp to [0,1] */
- t0=(t0<0.0f)?0.0f:((t0>1.0f)?1.0:t0);
- t1=(t1<0.0f)?0.0f:((t1>1.0f)?1.0:t1);
- }
+ CLAMP(t0, 0.0f, 1.0f);
+ CLAMP(t1, 0.0f, 1.0f);
-/*---test inside of tri---*/
- if(embedded_in_plane==0){
+ /*---test inside of tri---*/
/* plane intersection point */
- VecCopyf(point,vel);
- VecMulf(point,t0);
- VecAddf(point,point,p1);
- VecCopyf(temp,nor);
- VecMulf(temp,radius);
- VecSubf(point,point,temp);
+
+ point[0] = p1[0] + vel[0]*t0 - nor[0]*radius;
+ point[1] = p1[1] + vel[1]*t0 - nor[1]*radius;
+ point[2] = p1[2] + vel[2]*t0 - nor[2]*radius;
+
/* is the point in the tri? */
a=Inpf(e1,e1);
@@ -3866,14 +3902,19 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
y=e*a-d*b;
z=x+y-(a*c-b*b);
- if(( ((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y)) ) & 0x80000000){
+
+ if( z <= 0.0f && (x >= 0.0f && y >= 0.0f))
+ {
+ //( ((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y)) ) & 0x80000000){
*lambda=t0;
VecCopyf(ipoint,point);
return 1;
}
}
+
*lambda=1.0f;
+
/*---test points---*/
a=vel2=Inpf(vel,vel);
@@ -3881,73 +3922,42 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
VecSubf(temp,p1,v0);
b=2.0f*Inpf(vel,temp);
c=Inpf(temp,temp)-radius2;
- d=b*b-4*a*c;
-
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,v0);
- found_by_sweep=1;
- }
+ if(getLowestRoot(a, b, c, *lambda, lambda))
+ {
+ VecCopyf(ipoint,v0);
+ found_by_sweep=1;
}
/*v1*/
VecSubf(temp,p1,v1);
b=2.0f*Inpf(vel,temp);
c=Inpf(temp,temp)-radius2;
- d=b*b-4*a*c;
-
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,v1);
- found_by_sweep=1;
- }
+ if(getLowestRoot(a, b, c, *lambda, lambda))
+ {
+ VecCopyf(ipoint,v1);
+ found_by_sweep=1;
}
+
/*v2*/
VecSubf(temp,p1,v2);
b=2.0f*Inpf(vel,temp);
c=Inpf(temp,temp)-radius2;
- d=b*b-4*a*c;
-
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,v2);
- found_by_sweep=1;
- }
+ if(getLowestRoot(a, b, c, *lambda, lambda))
+ {
+ VecCopyf(ipoint,v2);
+ found_by_sweep=1;
}
/*---test edges---*/
+ VecSubf(e3,v2,v1); //wasnt yet calculated
+
+
/*e1*/
VecSubf(bv,v0,p1);
+
elen2 = Inpf(e1,e1);
edotv = Inpf(e1,vel);
edotbv = Inpf(e1,bv);
@@ -3955,27 +3965,18 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
a=elen2*(-Inpf(vel,vel))+edotv*edotv;
b=2.0f*(elen2*Inpf(vel,bv)-edotv*edotbv);
c=elen2*(radius2-Inpf(bv,bv))+edotbv*edotbv;
- d=b*b-4*a*c;
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- e=(edotv*t-edotbv)/elen2;
+ if(getLowestRoot(a, b, c, *lambda, &newLambda))
+ {
+ e=(edotv*newLambda-edotbv)/elen2;
- if((e>=0.0f) && (e<=1.0f)){
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,e1);
- VecMulf(ipoint,e);
- VecAddf(ipoint,ipoint,v0);
- found_by_sweep=1;
- }
+ if(e >= 0.0f && e <= 1.0f)
+ {
+ *lambda = newLambda;
+ VecCopyf(ipoint,e1);
+ VecMulf(ipoint,e);
+ VecAddf(ipoint,ipoint,v0);
+ found_by_sweep=1;
}
}
@@ -3988,32 +3989,27 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
a=elen2*(-Inpf(vel,vel))+edotv*edotv;
b=2.0f*(elen2*Inpf(vel,bv)-edotv*edotbv);
c=elen2*(radius2-Inpf(bv,bv))+edotbv*edotbv;
- d=b*b-4*a*c;
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- e=(edotv*t-edotbv)/elen2;
+ if(getLowestRoot(a, b, c, *lambda, &newLambda))
+ {
+ e=(edotv*newLambda-edotbv)/elen2;
- if((e>=0.0f) && (e<=1.0f)){
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,e2);
- VecMulf(ipoint,e);
- VecAddf(ipoint,ipoint,v0);
- found_by_sweep=1;
- }
+ if(e >= 0.0f && e <= 1.0f)
+ {
+ *lambda = newLambda;
+ VecCopyf(ipoint,e2);
+ VecMulf(ipoint,e);
+ VecAddf(ipoint,ipoint,v0);
+ found_by_sweep=1;
}
}
/*e3*/
- VecSubf(e3,v2,v1);
+ VecSubf(bv,v0,p1);
+ elen2 = Inpf(e1,e1);
+ edotv = Inpf(e1,vel);
+ edotbv = Inpf(e1,bv);
+
VecSubf(bv,v1,p1);
elen2 = Inpf(e3,e3);
edotv = Inpf(e3,vel);
@@ -4022,30 +4018,22 @@ int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, f
a=elen2*(-Inpf(vel,vel))+edotv*edotv;
b=2.0f*(elen2*Inpf(vel,bv)-edotv*edotbv);
c=elen2*(radius2-Inpf(bv,bv))+edotbv*edotbv;
- d=b*b-4*a*c;
- if(d>=0.0f){
- if(d==0.0f)
- t=-b/2*a;
- else{
- z=sqrt(d);
- x=(-b-z)*0.5/a;
- y=(-b+z)*0.5/a;
- t=x<y?x:y;
- }
- e=(edotv*t-edotbv)/elen2;
+ if(getLowestRoot(a, b, c, *lambda, &newLambda))
+ {
+ e=(edotv*newLambda-edotbv)/elen2;
- if((e>=0.0f) && (e<=1.0f)){
- if(t>0.0 && t < *lambda){
- *lambda=t;
- VecCopyf(ipoint,e3);
- VecMulf(ipoint,e);
- VecAddf(ipoint,ipoint,v1);
- found_by_sweep=1;
- }
+ if(e >= 0.0f && e <= 1.0f)
+ {
+ *lambda = newLambda;
+ VecCopyf(ipoint,e3);
+ VecMulf(ipoint,e);
+ VecAddf(ipoint,ipoint,v1);
+ found_by_sweep=1;
}
}
+
return found_by_sweep;
}
int AxialLineIntersectsTriangle(int axis, float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda)
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index fbcc56ac21d..ca7a376d3a2 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -382,7 +382,6 @@ void BLI_adddirstrings()
pwuser = getpwuid(files[num].s.st_uid);
if ( pwuser ) {
strcpy(files[num].owner, pwuser->pw_name);
- free(pwuser);
} else {
sprintf(files[num].owner, "%d", files[num].s.st_uid);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 3c629818b2d..090b1d7c6b6 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -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);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index ca91f1dc346..b59dd851dfe 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -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;
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index fe352610a40..3e618a483e3 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -451,7 +451,7 @@ void IMB_exr_begin_write(void *handle, char *filename, int width, int height, in
openexr_header_compression(&header, compress);
/* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
- header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43"));
+ header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43 and newer"));
data->ofile = new OutputFile(filename, header);
}
diff --git a/source/blender/include/BDR_drawaction.h b/source/blender/include/BDR_drawaction.h
index 91635123cb7..7cb0768e832 100644
--- a/source/blender/include/BDR_drawaction.h
+++ b/source/blender/include/BDR_drawaction.h
@@ -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
index 00000000000..d0ebd096ecb
--- /dev/null
+++ b/source/blender/include/BDR_gpencil.h
@@ -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
index 00000000000..418446313df
--- /dev/null
+++ b/source/blender/include/BIF_drawgpencil.h
@@ -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 */
diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h
index 2d751f56fc5..9f6751daeff 100644
--- a/source/blender/include/BIF_editaction.h
+++ b/source/blender/include/BIF_editaction.h
@@ -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);
@@ -141,6 +147,7 @@ void paste_actdata(void);
/* Group/Channel Operations */
struct bActionGroup *get_active_actiongroup(struct bAction *act);
void set_active_actiongroup(struct bAction *act, struct bActionGroup *agrp, short select);
+void actionbone_group_copycolors(struct bActionGroup *grp, short init_new);
void verify_pchan2achan_grouping(struct bAction *act, struct bPose *pose, char name[]);
void sync_pchan2achan_grouping(void);
void action_groups_group(short add_group);
@@ -166,6 +173,7 @@ void deselect_action_channels(short mode);
void deselect_actionchannels(struct bAction *act, short mode);
int select_channel(struct bAction *act, struct bActionChannel *achan, int selectmode);
void select_actionchannel_by_name(struct bAction *act, char *name, int select);
+void select_action_group_channels(struct bAction *act, struct bActionGroup *agrp);
void selectkeys_leftright (short leftright, short select_mode);
/* Action Markers */
@@ -174,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);
diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h
index e6cbe7bb69a..df514190270 100644
--- a/source/blender/include/BIF_resources.h
+++ b/source/blender/include/BIF_resources.h
@@ -591,6 +591,9 @@ void BIF_load_ui_colors (void);
char *BIF_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
char *BIF_ThemeColorsPup(int spacetype);
+/* only for Bone Color sets */
+char *BIF_ThemeColorSetsPup(short inc_custom);
+
void BIF_def_color (BIFColorID colorid, unsigned char r, unsigned char g, unsigned char b);
diff --git a/source/blender/include/BIF_space.h b/source/blender/include/BIF_space.h
index 37be4a9eafc..4b2b8e14bb6 100644
--- a/source/blender/include/BIF_space.h
+++ b/source/blender/include/BIF_space.h
@@ -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
+
diff --git a/source/blender/include/BSE_editaction_types.h b/source/blender/include/BSE_editaction_types.h
index c531383accc..be210415973 100644
--- a/source/blender/include/BSE_editaction_types.h
+++ b/source/blender/include/BSE_editaction_types.h
@@ -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
diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h
index a798224b35b..6f8b94d7cd1 100644
--- a/source/blender/include/blendef.h
+++ b/source/blender/include/blendef.h
@@ -409,6 +409,12 @@
#define B_ACTCOPYKEYS 710
#define B_ACTPASTEKEYS 711
+#define B_ACTCUSTCOLORS 712
+#define B_ACTCOLSSELECTOR 713
+#define B_ACTGRP_SELALL 714
+#define B_ACTGRP_ADDTOSELF 715
+#define B_ACTGRP_UNGROUP 716
+
/* TIME: 751 - 800 */
#define B_TL_REW 751
#define B_TL_PLAY 752
diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h
index 4e3b80134f9..720b856a149 100644
--- a/source/blender/include/transform.h
+++ b/source/blender/include/transform.h
@@ -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);
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 18d2a1cb6f3..d7969a7379b 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -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_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index a467722e8e1..ac9761f165d 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -196,9 +196,7 @@ typedef struct bVisibilityActuator {
} bVisibilityActuator;
typedef struct bTwoDFilterActuator{
- char pad[2];
- /* bitwise flag for enabling or disabling depth(bit 0) and luminance(bit 1) */
- short texture_flag;
+ char pad[4];
/* Tells what type of 2D Filter */
short type;
/* (flag == 0) means 2D filter is activate and
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
new file mode 100644
index 00000000000..eafd886981b
--- /dev/null
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -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 */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index bc30a12ff27..a8694dfb7f5 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -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 {
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3de5b0ff5ba..cd1c047dac9 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -116,6 +116,7 @@ typedef struct ThemeWireColor {
/* flags for ThemeWireColor */
#define TH_WIRECOLOR_CONSTCOLS (1<<0)
+#define TH_WIRECOLOR_TEXTCOLS (1<<1)
/* A theme */
typedef struct bTheme {
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index c21d629be83..135272b9ac2 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -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
+
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 83f4e633fa1..3818d66b39c 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -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 */
diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c
index 633badb759d..71675ade605 100644
--- a/source/blender/python/api2_2x/Blender.c
+++ b/source/blender/python/api2_2x/Blender.c
@@ -709,7 +709,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" );
}
diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c
index 799735c2062..468263c4208 100644
--- a/source/blender/python/api2_2x/Library.c
+++ b/source/blender/python/api2_2x/Library.c
@@ -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}
};
diff --git a/source/blender/python/api2_2x/Particle.c b/source/blender/python/api2_2x/Particle.c
index 95de9757b87..2c2e724129e 100644
--- a/source/blender/python/api2_2x/Particle.c
+++ b/source/blender/python/api2_2x/Particle.c
@@ -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;
diff --git a/source/blender/python/api2_2x/doc/Ipo.py b/source/blender/python/api2_2x/doc/Ipo.py
index c479926ccf3..d1c72f8cb86 100644
--- a/source/blender/python/api2_2x/doc/Ipo.py
+++ b/source/blender/python/api2_2x/doc/Ipo.py
@@ -250,7 +250,7 @@ class Ipo:
OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var,
Disp.
3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ,
- dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ,
+ dRotX, dRotY, dRotZ, ScaleX, ScaleY, ScaleZ, dScaleX, dScaleY, dScaleZ,
Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping,
RDamp, Perm.
4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt.
@@ -289,7 +289,7 @@ class Ipo:
OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var,
Disp.
3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ,
- dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ,
+ dRotX, dRotY, dRotZ, ScaleX, ScaleY, ScaleZ, dScaleX, dScaleY, dScaleZ,
Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping,
RDamp, Perm.
4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt.
diff --git a/source/blender/python/api2_2x/doc/LibData.py b/source/blender/python/api2_2x/doc/LibData.py
index 47bd7fdb763..daa6a186531 100644
--- a/source/blender/python/api2_2x/doc/LibData.py
+++ b/source/blender/python/api2_2x/doc/LibData.py
@@ -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:
"""
diff --git a/source/blender/python/api2_2x/doc/Particle.py b/source/blender/python/api2_2x/doc/Particle.py
index 192ecd5355b..511ad81b45f 100644
--- a/source/blender/python/api2_2x/doc/Particle.py
+++ b/source/blender/python/api2_2x/doc/Particle.py
@@ -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.
"""
diff --git a/source/blender/python/api2_2x/doc/Render.py b/source/blender/python/api2_2x/doc/Render.py
index 475a4fc5b10..d4dc83e84a0 100644
--- a/source/blender/python/api2_2x/doc/Render.py
+++ b/source/blender/python/api2_2x/doc/Render.py
@@ -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):
diff --git a/source/blender/python/api2_2x/sceneRender.c b/source/blender/python/api2_2x/sceneRender.c
index a6f35bf4d5d..6fc3a2b18d1 100644
--- a/source/blender/python/api2_2x/sceneRender.c
+++ b/source/blender/python/api2_2x/sceneRender.c
@@ -987,7 +987,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;
}
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 67be0ce4c00..4520e4c10bb 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -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);
+ }
+ }
}
}
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 0928042729a..5b69323667e 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -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)));
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 579905315bb..c91c9e2f799 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -3545,7 +3545,7 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *col= NULL;
- int pixsize= 0;
+ int pixsize= 3;
switch(rpass->passtype) {
case SCE_PASS_RGBA:
@@ -3580,6 +3580,10 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
col= &shr->mist;
pixsize= 1;
break;
+ case SCE_PASS_Z:
+ col= &shr->z;
+ pixsize= 1;
+ break;
case SCE_PASS_VECTOR:
{
@@ -3612,14 +3616,18 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
for(samp= 1; samp<R.osa; samp++, fp+=delta) {
col[0]+= fp[0];
- col[1]+= fp[1];
- col[2]+= fp[2];
- if(pixsize) col[3]+= fp[3];
+ if(pixsize>1) {
+ col[1]+= fp[1];
+ col[2]+= fp[2];
+ if(pixsize==4) col[3]+= fp[3];
+ }
}
col[0]*= weight;
- col[1]*= weight;
- col[2]*= weight;
- if(pixsize) col[3]*= weight;
+ if(pixsize>1) {
+ col[1]*= weight;
+ col[2]*= weight;
+ if(pixsize==4) col[3]*= weight;
+ }
}
}
@@ -3973,7 +3981,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* general shader info, passes */
shade_sample_initialize(&ssamp, pa, rl);
- addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
+ addpassflag= rl->passflag & ~(SCE_PASS_COMBINED);
addzbuf= rl->passflag & SCE_PASS_Z;
if(R.osa)
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 7eff79fec88..529a795a101 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -513,7 +513,6 @@ void do_common_editbuts(unsigned short event) // old name, is a mix of object an
} else {
editmesh_deselect_by_material(G.obedit->actcol-1);
}
- allqueue(REDRAWVIEW3D, 0);
}
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
nu= editNurb.first;
@@ -553,8 +552,9 @@ void do_common_editbuts(unsigned short event) // old name, is a mix of object an
nu= nu->next;
}
BIF_undo_push("Select material index");
- allqueue(REDRAWVIEW3D, 0);
}
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
}
countall();
break;
@@ -5153,32 +5153,6 @@ static void verify_posegroup_groupname(void *arg1, void *arg2)
BLI_uniquename(&pose->agroups, grp, "Group", offsetof(bActionGroup, name), 32);
}
-static char *build_colorsets_menustr ()
-{
- DynStr *pupds= BLI_dynstr_new();
- char *str;
- char buf[48];
- int i;
-
- /* add title first (and the "default" entry) */
- BLI_dynstr_append(pupds, "Bone Color Set%t|Default Colors%x0|");
-
- /* loop through set indices, adding them */
- for (i=1; i<21; i++) {
- sprintf(buf, "%d - Theme Color Set%%x%d|", i, i);
- BLI_dynstr_append(pupds, buf);
- }
-
- /* add the 'custom' entry */
- BLI_dynstr_append(pupds, "Custom Set %x-1");
-
- /* convert to normal MEM_malloc'd string */
- str= BLI_dynstr_get_cstring(pupds);
- BLI_dynstr_free(pupds);
-
- return str;
-}
-
static void editing_panel_links(Object *ob)
{
uiBlock *block;
@@ -5338,32 +5312,14 @@ static void editing_panel_links(Object *ob)
/* color set for 'active' group */
if (pose->active_group && grp) {
uiBlockBeginAlign(block);
- menustr= build_colorsets_menustr();
+ menustr= BIF_ThemeColorSetsPup(1);
uiDefButI(block, MENU,B_POSEGRP_RECALC, menustr, xco,85,140,19, &grp->customCol, -1, 20, 0.0, 0.0, "Index of set of Custom Colors to shade Group's bones with. 0 = Use Default Color Scheme, -1 = Use Custom Color Scheme");
MEM_freeN(menustr);
/* show color-selection/preview */
if (grp->customCol) {
- if (grp->customCol > 0) {
- /* copy theme colors on-to group's custom color in case user tries to edit color */
- bTheme *btheme= U.themes.first;
- ThemeWireColor *col_set= &btheme->tarm[(grp->customCol - 1)];
-
- memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
- }
- else {
- /* init custom colors with a generic multi-color rgb set, if not initialised already */
- if (grp->cs.solid[0] == 0) {
- /* define for setting colors in theme below */
- #define SETCOL(col, r, g, b, a) col[0]=r; col[1]=g; col[2]= b; col[3]= a;
-
- SETCOL(grp->cs.solid, 0xff, 0x00, 0x00, 255);
- SETCOL(grp->cs.select, 0x81, 0xe6, 0x14, 255);
- SETCOL(grp->cs.active, 0x18, 0xb6, 0xe0, 255);
-
- #undef SETCOL
- }
- }
+ /* do color copying/init (to stay up to date) */
+ actionbone_group_copycolors(grp, 1);
/* color changing */
uiDefButC(block, COL, B_POSEGRP_MCUSTOM, "", xco, 65, 30, 19, grp->cs.solid, 0, 0, 0, 0, "Color to use for surface of bones");
diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c
index cc4df06e22d..6b29a05bd22 100644
--- a/source/blender/src/buttons_logic.c
+++ b/source/blender/src/buttons_logic.c
@@ -2062,7 +2062,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
coa->time = 0;
uiDefButS(block, MENU, 1, str, xco+10, yco-65, 70, 19, &coa->flag, 0.0, 0.0, 0, 0, "");
- uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefButS(block, NUM, 0, "damp", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "Damping factor: time constant (in frame) of low pass filter");
uiDefBut(block, LABEL, 0, "Min", xco+80, yco-45, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
uiDefBut(block, LABEL, 0, "Max", xco+80+(width-90)/2, yco-45, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
@@ -2084,7 +2084,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
str= "Direction %t|None %x0|X axis %x1|Y axis %x2|Z axis %x4|-X axis %x8|-Y axis %x16|-Z axis %x32";
uiDefButS(block, MENU, B_REDR, str, xco+10, yco-65, 70, 19, &coa->mode, 0.0, 0.0, 0, 0, "Set the direction of the ray");
- uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefButS(block, NUM, 0, "damp", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "Damping factor: time constant (in frame) of low pass filter");
uiDefBut(block, LABEL, 0, "Range", xco+80, yco-45, (width-115)/2, 19, NULL, 0.0, 0.0, 0, 0, "Set the maximum length of ray");
uiDefButBitS(block, TOG, ACT_CONST_DISTANCE, B_REDR, "Dist", xco+80+(width-115)/2, yco-45, (width-115)/2, 19, &coa->flag, 0.0, 0.0, 0, 0, "Force distance of object to point of impact of ray");
@@ -2124,7 +2124,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
str= "Direction %t|None %x0|X axis %x1|Y axis %x2|Z axis %x4";
uiDefButS(block, MENU, B_REDR, str, xco+10, yco-65, 70, 19, &coa->mode, 0.0, 0.0, 0, 0, "Select the axis to be aligned along the reference direction");
- uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefButS(block, NUM, 0, "damp", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "Damping factor: time constant (in frame) of low pass filter");
uiDefBut(block, LABEL, 0, "X", xco+80, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
uiDefBut(block, LABEL, 0, "Y", xco+80+(width-115)/3, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
uiDefBut(block, LABEL, 0, "Z", xco+80+2*(width-115)/3, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
@@ -2133,7 +2133,9 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
uiDefButF(block, NUM, 0, "", xco+80+(width-115)/3, yco-65, (width-115)/3, 19, &coa->maxrot[1], -2000.0, 2000.0, 10, 0, "Y component of reference direction");
uiDefButF(block, NUM, 0, "", xco+80+2*(width-115)/3, yco-65, (width-115)/3, 19, &coa->maxrot[2], -2000.0, 2000.0, 10, 0, "Z component of reference direction");
- uiDefButS(block, NUM, 0, "time", xco+10, yco-84, 70+(width-115)/3, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited");
+ uiDefButS(block, NUM, 0, "time", xco+10, yco-84, 70, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited");
+ uiDefButF(block, NUM, 0, "min", xco+80, yco-84, (width-115)/2, 19, &(coa->minloc[0]), 0.0, 180.0, 10, 1, "Minimum angle (in degree) to maintain with target direction. No correction is done if angle with target direction is between min and max");
+ uiDefButF(block, NUM, 0, "max", xco+80+(width-115)/2, yco-84, (width-115)/2, 19, &(coa->maxloc[0]), 0.0, 180.0, 10, 1, "Maximum angle (in degree) allowed with target direction. No correction is done if angle with target direction is between min and max");
}
str= "Constraint Type %t|Location %x0|Distance %x1|Orientation %x2";
but = uiDefButS(block, MENU, B_REDR, str, xco+40, yco-23, (width-80), 19, &coa->type, 0.0, 0.0, 0, 0, "");
@@ -2536,11 +2538,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
break;
case ACT_2DFILTER_CUSTOMFILTER:
uiDefButI(block, NUM, B_REDR, "Pass Number:", xco+30,yco-44,width-60,19,&tdfa->int_arg,0.0,MAX_RENDER_PASS-1,0.0,0.0,"Set motion blur value");
- uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "Script: ", xco+30,yco-64,width/2-32, 19, &tdfa->text, "");
- uiDefButS(block, TOG|BIT|0, B_REDR, "Depth", xco+width/2+2 , yco - 64, width/4-16 , 19,
- &tdfa->texture_flag, 0.0, 0.0, 0, 0, "Includes Depth Texture (bgl_DepthTexture)");
- uiDefButS(block, TOG|BIT|1, B_REDR, "Luminance", xco+3*width/4-14 , yco - 64, width/4-16 , 19,
- &tdfa->texture_flag, 0.0, 0.0, 0, 0, "Includes Luminance Texture (bgl_LuminanceTexture)");
+ uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "Script: ", xco+30,yco-64,width-60, 19, &tdfa->text, "");
break;
}
diff --git a/source/blender/src/buttons_scene.c b/source/blender/src/buttons_scene.c
index a58d44538a2..8b35f90ea9d 100644
--- a/source/blender/src/buttons_scene.c
+++ b/source/blender/src/buttons_scene.c
@@ -137,36 +137,42 @@ static void load_new_sample(char *str) /* called from fileselect */
bSample *sample, *newsample;
sound = G.buts->lockpoin;
+
+ /* No Sound or Selected the same sample as we alredy have, just ignore */
+ if (sound==NULL || str==sound->name)
+ return;
+
+ if (sizeof(sound->sample->name) < strlen(str)) {
+ error("Path too long: %s", str);
+ return;
+ }
+
+ // save values
+ sample = sound->sample;
+ strcpy(name, sound->sample->name);
+ strcpy(sound->name, str);
+ sound_set_sample(sound, NULL);
+ sound_initialize_sample(sound);
- if (sound) {
- // save values
- sample = sound->sample;
- strcpy(name, sound->sample->name);
-
- strcpy(sound->name, str);
- sound_set_sample(sound, NULL);
- sound_initialize_sample(sound);
-
- if (sound->sample->type == SAMPLE_INVALID) {
- error("Not a valid sample: %s", str);
+ if (sound->sample->type == SAMPLE_INVALID) {
+ error("Not a valid sample: %s", str);
- newsample = sound->sample;
+ newsample = sound->sample;
- // restore values
- strcpy(sound->name, name);
- sound_set_sample(sound, sample);
+ // restore values
+ strcpy(sound->name, name);
+ sound_set_sample(sound, sample);
- // remove invalid sample
+ // remove invalid sample
- sound_free_sample(newsample);
- BLI_remlink(samples, newsample);
- MEM_freeN(newsample);
- }
+ sound_free_sample(newsample);
+ BLI_remlink(samples, newsample);
+ MEM_freeN(newsample);
+ return;
}
-
+
BIF_undo_push("Load new audio file");
allqueue(REDRAWBUTSSCENE, 0);
-
}
@@ -403,7 +409,7 @@ static void sound_panel_sound(bSound *sound)
sample = sound->sample;
/* info string */
- if (sound->sample && sound->sample->len) {
+ if (sound->sample && sound->sample->len && sound->sample->channels && sound->sample->bits) {
char *tmp;
if (sound->sample->channels == 1) tmp= "Mono";
else if (sound->sample->channels == 2) tmp= "Stereo";
@@ -1174,18 +1180,18 @@ static void seq_panel_proxy()
130,140,120,19, &last_seq->flag,
0.0, 21.0, 100, 0,
"Use a custom directory to store data");
- }
- if (last_seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
- uiDefIconBut(block, BUT, B_SEQ_SEL_PROXY_DIR,
- ICON_FILESEL, 10, 120, 20, 20, 0, 0, 0, 0, 0,
- "Select the directory/name for "
- "the proxy storage");
+ if (last_seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
+ uiDefIconBut(block, BUT, B_SEQ_SEL_PROXY_DIR,
+ ICON_FILESEL, 10, 120, 20, 20, 0, 0, 0, 0, 0,
+ "Select the directory/name for "
+ "the proxy storage");
- uiDefBut(block, TEX,
- B_SEQ_BUT_RELOAD, "Dir: ",
- 30,120,220,20, last_seq->strip->proxy->dir,
- 0.0, 160.0, 100, 0, "");
+ uiDefBut(block, TEX,
+ B_SEQ_BUT_RELOAD, "Dir: ",
+ 30,120,220,20, last_seq->strip->proxy->dir,
+ 0.0, 160.0, 100, 0, "");
+ }
}
if (last_seq->flag & SEQ_USE_PROXY) {
diff --git a/source/blender/src/drawaction.c b/source/blender/src/drawaction.c
index 89466151a39..9b1af3f1a06 100644
--- a/source/blender/src/drawaction.c
+++ b/source/blender/src/drawaction.c
@@ -32,6 +32,7 @@
#include <math.h>
#include <stdlib.h>
+#include <string.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -56,6 +57,8 @@
#include "DNA_space_types.h"
#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"
@@ -72,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"
@@ -81,6 +85,7 @@
#include "BDR_drawaction.h"
#include "BDR_editcurve.h"
+#include "BDR_gpencil.h"
#include "BSE_drawnla.h"
#include "BSE_drawipo.h"
@@ -620,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 */
@@ -825,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) {
@@ -863,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 */
@@ -897,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;
}
}
@@ -928,12 +977,55 @@ static void draw_channel_strips(void)
void do_actionbuts(unsigned short event)
{
switch(event) {
+ /* general */
case REDRAWVIEW3D:
allqueue(REDRAWVIEW3D, 0);
break;
case B_REDR:
allqueue(REDRAWACTION, 0);
break;
+
+ /* action-groups */
+ case B_ACTCUSTCOLORS: /* only when of the color wells is edited */
+ {
+ bActionGroup *agrp= get_active_actiongroup(G.saction->action);
+
+ if (agrp)
+ agrp->customCol= -1;
+
+ allqueue(REDRAWACTION, 0);
+ }
+ break;
+ case B_ACTCOLSSELECTOR: /* sync color set after using selector */
+ {
+ bActionGroup *agrp= get_active_actiongroup(G.saction->action);
+
+ if (agrp)
+ actionbone_group_copycolors(agrp, 1);
+
+ allqueue(REDRAWACTION, 0);
+ }
+ break;
+ case B_ACTGRP_SELALL: /* select all grouped channels */
+ {
+ bAction *act= G.saction->action;
+ bActionGroup *agrp= get_active_actiongroup(act);
+
+ /* select all in group, then reselect/activate group as the previous operation clears that */
+ select_action_group_channels(act, agrp);
+ agrp->flag |= (AGRP_ACTIVE|AGRP_SELECTED);
+
+ allqueue(REDRAWACTION, 0);
+ }
+ break;
+ case B_ACTGRP_ADDTOSELF: /* add all selected action channels to self */
+ action_groups_group(0);
+ break;
+ case B_ACTGRP_UNGROUP: /* remove channels from active group */
+ // FIXME: todo...
+ printf("FIXME: remove achans from active Action-Group not implemented yet! \n");
+ break;
+
}
}
@@ -941,14 +1033,68 @@ void do_actionbuts(unsigned short event)
static void action_panel_properties(short cntrl) // ACTION_HANDLER_PROPERTIES
{
uiBlock *block;
-
+ void *data;
+ short datatype;
+
block= uiNewBlock(&curarea->uiblocks, "action_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
uiSetPanelHandler(ACTION_HANDLER_PROPERTIES); // for close and esc
- if (uiNewPanel(curarea, block, "Transform Properties", "Action", 10, 230, 318, 204)==0)
+
+ /* get datatype */
+ data= get_action_context(&datatype);
+ //if (data == NULL) return;
+
+ if (uiNewPanel(curarea, block, "Active Channel Properties", "Action", 10, 230, 318, 204)==0)
return;
-
- uiDefBut(block, LABEL, 0, "test text", 10,180,300,19, 0, 0, 0, 0, 0, "");
+
+ /* currently, only show data for actions */
+ if (datatype == ACTCONT_ACTION) {
+ bActionGroup *agrp= get_active_actiongroup(data);
+ //bActionChannel *achan= get_hilighted_action_channel(data);
+ char *menustr;
+
+ /* only for action-groups */
+ if (agrp) {
+ /* general stuff */
+ uiDefBut(block, LABEL, 1, "Action Group:", 10, 180, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, TEX, B_REDR, "Name: ", 10,160,150,20, agrp->name, 0.0, 31.0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, AGRP_EXPANDED, B_REDR, "Expanded", 170, 160, 75, 20, &agrp->flag, 0, 0, 0, 0, "Action Group is expanded");
+ uiDefButBitI(block, TOG, AGRP_PROTECTED, B_REDR, "Protected", 245, 160, 75, 20, &agrp->flag, 0, 0, 0, 0, "Action Group is protected");
+ uiBlockEndAlign(block);
+
+ /* color stuff */
+ uiDefBut(block, LABEL, 1, "Group Colors:", 10, 107, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ menustr= BIF_ThemeColorSetsPup(1);
+ uiDefButI(block, MENU,B_ACTCOLSSELECTOR, menustr, 10,85,150,19, &agrp->customCol, -1, 20, 0.0, 0.0, "Index of set of Custom Colors to shade Group's bones with. 0 = Use Default Color Scheme, -1 = Use Custom Color Scheme");
+ MEM_freeN(menustr);
+
+ /* show color-selection/preview */
+ if (agrp->customCol) {
+ /* do color copying/init (to stay up to date) */
+ actionbone_group_copycolors(agrp, 1);
+
+ /* color changing */
+ uiDefButC(block, COL, B_ACTCUSTCOLORS, "", 10, 65, 50, 19, agrp->cs.active, 0, 0, 0, 0, "Color to use for 'top-level' channels");
+ uiDefButC(block, COL, B_ACTCUSTCOLORS, "", 60, 65, 50, 19, agrp->cs.select, 0, 0, 0, 0, "Color to use for '2nd-level' channels");
+ uiDefButC(block, COL, B_ACTCUSTCOLORS, "", 110, 65, 50, 19, agrp->cs.solid, 0, 0, 0, 0, "Color to use for '3rd-level' channels");
+ }
+ uiBlockEndAlign(block);
+
+ /* commands for active group */
+ uiDefBut(block, BUT, B_ACTGRP_SELALL, "Select Grouped", 170,85,150,20, 0, 21, 0, 0, 0, "Select all action-channels belonging to this group (same as doing Ctrl-Shift-LMB)");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_ACTGRP_ADDTOSELF, "Add to Group", 170,60,150,20, 0, 21, 0, 0, 0, "Add selected action-channels to this group");
+ uiDefBut(block, BUT, B_ACTGRP_UNGROUP, "Un-Group", 170,40,150,20, 0, 21, 0, 0, 0, "Remove selected action-channels from this group (unimplemented)");
+ uiBlockEndAlign(block);
+ }
+ }
+ else {
+ /* Currently, there isn't anything to display for these types ... */
+ }
}
static void action_blockhandlers(ScrArea *sa)
@@ -976,6 +1122,7 @@ void drawactionspace(ScrArea *sa, void *spacedata)
{
bAction *act = NULL;
Key *key = NULL;
+ bGPdata *gpd = NULL;
void *data;
short datatype;
@@ -991,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
@@ -1351,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;
@@ -1429,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)
@@ -1575,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
index 00000000000..55d0464b9af
--- /dev/null
+++ b/source/blender/src/drawgpencil.c
@@ -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);
+}
+
+/* ************************************************** */
diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c
index 1169062fdd0..3a73ee84ead 100644
--- a/source/blender/src/drawnode.c
+++ b/source/blender/src/drawnode.c
@@ -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"
@@ -65,8 +66,11 @@
#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 */
diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c
index 045bf292446..1a469e8b366 100644
--- a/source/blender/src/drawobject.c
+++ b/source/blender/src/drawobject.c
@@ -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);
diff --git a/source/blender/src/drawseq.c b/source/blender/src/drawseq.c
index e554b91dd52..c8c74ad8279 100644
--- a/source/blender/src/drawseq.c
+++ b/source/blender/src/drawseq.c
@@ -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;
diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c
index f595a101f63..14434504e7a 100644
--- a/source/blender/src/drawview.c
+++ b/source/blender/src/drawview.c
@@ -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"
@@ -111,6 +112,7 @@
#include "BIF_butspace.h"
#include "BIF_drawimage.h"
+#include "BIF_drawgpencil.h"
#include "BIF_editgroup.h"
#include "BIF_editarmature.h"
#include "BIF_editmesh.h"
@@ -137,6 +139,7 @@
#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();
diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c
index f93a1526e3c..3251cb33b53 100644
--- a/source/blender/src/editaction.c
+++ b/source/blender/src/editaction.c
@@ -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;
+ }
}
}
@@ -1114,6 +1186,38 @@ void action_groups_ungroup (void)
allqueue(REDRAWACTION, 0);
}
+/* Copy colors from a specified theme's color set to an Action/Bone Group */
+void actionbone_group_copycolors (bActionGroup *grp, short init_new)
+{
+ /* error checking */
+ if (grp == NULL)
+ return;
+
+ /* only do color copying if using a custom color */
+ if (grp->customCol) {
+ if (grp->customCol > 0) {
+ /* copy theme colors on-to group's custom color in case user tries to edit color */
+ bTheme *btheme= U.themes.first;
+ ThemeWireColor *col_set= &btheme->tarm[(grp->customCol - 1)];
+
+ memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
+ }
+ else if (init_new) {
+ /* init custom colors with a generic multi-color rgb set, if not initialised already (and allowed to do so) */
+ if (grp->cs.solid[0] == 0) {
+ /* define for setting colors in theme below */
+ #define SETCOL(col, r, g, b, a) col[0]=r; col[1]=g; col[2]= b; col[3]= a;
+
+ SETCOL(grp->cs.solid, 0xff, 0x00, 0x00, 255);
+ SETCOL(grp->cs.select, 0x81, 0xe6, 0x14, 255);
+ SETCOL(grp->cs.active, 0x18, 0xb6, 0xe0, 255);
+
+ #undef SETCOL
+ }
+ }
+ }
+}
+
/* This function is used when inserting keyframes for pose-channels. It assigns the
* action-channel with the nominated name to a group with the same name as that of
* the pose-channel with the nominated name.
@@ -1160,34 +1264,9 @@ void verify_pchan2achan_grouping (bAction *act, bPose *pose, char name[])
/* copy name */
sprintf(grp->name, agrp->name);
- /* deal with group-color copying */
- if (agrp->customCol) {
- if (agrp->customCol > 0) {
- /* copy theme colors on-to group's custom color in case user tries to edit color */
- bTheme *btheme= U.themes.first;
- ThemeWireColor *col_set= &btheme->tarm[(agrp->customCol - 1)];
-
- memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
- }
- else {
- /* init custom colors with a generic multi-color rgb set, if not initialised already */
- if (agrp->cs.solid[0] == 0) {
- /* define for setting colors in theme below */
- #define SETCOL(col, r, g, b, a) col[0]=r; col[1]=g; col[2]= b; col[3]= a;
-
- SETCOL(grp->cs.solid, 0xff, 0x00, 0x00, 255);
- SETCOL(grp->cs.select, 0x81, 0xe6, 0x14, 255);
- SETCOL(grp->cs.active, 0x18, 0xb6, 0xe0, 255);
-
- #undef SETCOL
- }
- else {
- /* just copy color set specified */
- memcpy(&grp->cs, &agrp->cs, sizeof(ThemeWireColor));
- }
- }
- }
- grp->customCol= agrp->customCol;
+ /* deal with group-color copying (grp is destination, agrp is source) */
+ memcpy(grp, agrp, sizeof(bActionGroup));
+ actionbone_group_copycolors(grp, 1);
BLI_addtail(&act->groups, grp);
}
@@ -1300,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 */
@@ -1391,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 */
@@ -1401,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);
}
@@ -1414,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 */
@@ -1449,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 */
@@ -1459,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);
}
@@ -1543,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);
@@ -1566,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 */
@@ -1692,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);
@@ -1730,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);
@@ -2089,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) {
@@ -2187,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);
@@ -2225,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;
@@ -2338,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;
@@ -2386,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);
@@ -2517,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);
@@ -2557,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;
@@ -2630,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;
@@ -2654,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;
@@ -2677,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;
@@ -2697,6 +2855,51 @@ 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)
+{
+ bActionChannel *achan;
+
+ /* error checking */
+ if (ELEM(NULL, act, agrp))
+ return;
+
+ /* deselect all other channels */
+ deselect_actionchannels(act, 0);
+
+ /* only select channels in group */
+ for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
+ select_channel(act, achan, SELECT_ADD);
+
+ /* messy... set active bone */
+ select_poseelement_by_name(achan->name, 1);
+ }
+}
+
/* ----------------------------------------- */
/* De-selects or inverts the selection of Channels in a given Action
@@ -2819,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?
}
@@ -2834,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 */
@@ -2917,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;
@@ -2942,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);
@@ -3029,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 */
@@ -3079,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) {
@@ -3088,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);
}
@@ -3170,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;
@@ -3202,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;
+ }
}
}
}
@@ -3243,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)) ) {
@@ -3315,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' */
@@ -3431,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))) {
@@ -3452,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 */
@@ -3474,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);
+ }
}
}
@@ -3504,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;
@@ -3514,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);
@@ -3586,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;
}
@@ -3609,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)
@@ -3625,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);
@@ -3641,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;
@@ -3672,17 +3971,8 @@ static void mouse_actionchannels (short mval[])
select_action_group(act, agrp, SELECT_INVERT);
}
else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
- bActionChannel *achan;
-
/* select all in group (and deselect everthing else) */
- deselect_actionchannels(act, 0);
-
- for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
- select_channel(act, achan, SELECT_ADD);
-
- /* messy... set active bone */
- select_poseelement_by_name(achan->name, 1);
- }
+ select_action_group_channels(act, agrp);
select_action_group(act, agrp, SELECT_ADD);
}
else {
@@ -3796,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;
}
@@ -4462,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();
@@ -4682,11 +4990,13 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case NKEY:
if (G.qual==0) {
- numbuts_action();
-
- /* no panel (yet). current numbuts are not easy to put in panel... */
- //add_blockhandler(curarea, ACTION_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
- //scrarea_queue_winredraw(curarea);
+ /* panel will not always show useful info! */
+ if (mval[0] > ACTWIDTH) {
+ add_blockhandler(curarea, ACTION_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ scrarea_queue_winredraw(curarea);
+ }
+ else
+ numbuts_action();
}
break;
@@ -4810,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
index 00000000000..b91c5a8b332
--- /dev/null
+++ b/source/blender/src/editaction_gpencil.c
@@ -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;
+ }
+}
+
+/* ***************************************** */
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c
index 9eef61e11f9..188f7476728 100644
--- a/source/blender/src/editmesh.c
+++ b/source/blender/src/editmesh.c
@@ -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();
diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c
index 4c7334c55e0..5c137e67c1a 100644
--- a/source/blender/src/editnode.c
+++ b/source/blender/src/editnode.c
@@ -82,6 +82,7 @@
#include "BLI_storage_types.h"
#include "BDR_editobject.h"
+#include "BDR_gpencil.h"
#include "RE_pipeline.h"
#include "IMB_imbuf_types.h"
@@ -2305,6 +2306,7 @@ static int node_uiDoBlocks(ScrArea *sa, short event)
SpaceNode *snode= sa->spacedata.first;
ListBase *lb= &sa->uiblocks;
ListBase listb= *lb;
+ uiBlock *block;
bNode *node;
rctf rect;
void *prev, *next;
@@ -2319,13 +2321,36 @@ static int node_uiDoBlocks(ScrArea *sa, short event)
return UI_NOTHING;
}
+ /* evil hack: try to do grease-pencil floating panel (like for nodes) */
+ block= uiGetBlock("nodes_panel_gpencil", sa);
+ if (block) {
+ /* try to process events here... if failed, just carry on */
+ /* when there's menus, the prev pointer becomes zero! */
+ prev= ((struct Link *)block)->prev;
+ next= ((struct Link *)block)->next;
+ ((struct Link *)block)->prev= NULL;
+ ((struct Link *)block)->next= NULL;
+
+ lb->first= lb->last= block;
+ retval= uiDoBlocks(lb, event, 1);
+
+ ((struct Link *)block)->prev= prev;
+ ((struct Link *)block)->next= next;
+
+ *lb= listb;
+
+ /* if something happened, get the heck outta here */
+ if (retval != UI_NOTHING)
+ return retval;
+ }
+
+
rect.xmin -= 2.0f;
rect.ymin -= 2.0f;
rect.xmax = rect.xmin + 4.0f;
rect.ymax = rect.ymin + 4.0f;
for(node= snode->edittree->nodes.first; node; node= node->next) {
- uiBlock *block;
char str[32];
/* retreive unique block name, see also drawnode.c */
@@ -2369,14 +2394,16 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(snode->nodetree==NULL) return;
if(val) {
-
- if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;
-
+ if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;
+
fromlib= (snode->id && snode->id->lib);
switch(event) {
case LEFTMOUSE:
- if(fromlib) {
+ if(gpencil_do_paint(sa)) {
+ return;
+ }
+ else if(fromlib) {
if(node_mouse_groupheader(snode)==0)
node_mouse_select(snode, event);
}
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
index 2e5785eaab8..6af4f47ed11 100644
--- a/source/blender/src/editobject.c
+++ b/source/blender/src/editobject.c
@@ -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/editsound.c b/source/blender/src/editsound.c
index 1cb7ec276cb..05eb094a7c2 100644
--- a/source/blender/src/editsound.c
+++ b/source/blender/src/editsound.c
@@ -148,7 +148,7 @@ void winqreadsoundspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
first= 0;
CFRA= cfra;
update_for_newframe();
- force_draw_plus(SPACE_VIEW3D, 1);
+ force_draw_all(0);
}
else PIL_sleep_ms(30);
diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c
new file mode 100644
index 00000000000..fa32b0ac7d4
--- /dev/null
+++ b/source/blender/src/gpencil.c
@@ -0,0 +1,1290 @@
+/**
+ * $Id: gpencil.c 14881 2008-05-18 10:41:42Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_butspace.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_toets.h"
+
+#include "BDR_gpencil.h"
+#include "BIF_drawgpencil.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+
+#include "PIL_time.h" /* sleep */
+#include "mydevice.h"
+
+/* ************************************************** */
+/* GENERAL STUFF */
+
+/* --------- Memory Management ------------ */
+
+/* Free strokes belonging to a gp-frame */
+void free_gpencil_strokes (bGPDframe *gpf)
+{
+ bGPDstroke *gps, *gpsn;
+
+ /* error checking */
+ if (gpf == NULL) return;
+
+ /* free strokes */
+ for (gps= gpf->strokes.first; gps; gps= gpsn) {
+ gpsn= gps->next;
+
+ /* free stroke memory arrays, then stroke itself */
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+}
+
+/* Free all of a gp-layer's frames */
+void free_gpencil_frames (bGPDlayer *gpl)
+{
+ bGPDframe *gpf, *gpfn;
+
+ /* error checking */
+ if (gpl == NULL) return;
+
+ /* free frames */
+ for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+ gpfn= gpf->next;
+
+ /* free strokes and their associated memory */
+ free_gpencil_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+}
+
+/* Free all of the gp-layers for a viewport (list should be &G.vd->gpd or so) */
+void free_gpencil_layers (ListBase *list)
+{
+ bGPDlayer *gpl, *gpln;
+
+ /* error checking */
+ if (list == NULL) return;
+
+ /* delete layers*/
+ for (gpl= list->first; gpl; gpl= gpln) {
+ gpln= gpl->next;
+
+ /* free layers and their data */
+ free_gpencil_frames(gpl);
+ BLI_freelinkN(list, gpl);
+ }
+}
+
+/* Free gp-data and all it's related data */
+void free_gpencil_data (bGPdata *gpd)
+{
+ /* free layers then data itself */
+ free_gpencil_layers(&gpd->layers);
+ MEM_freeN(gpd);
+}
+
+/* -------- Container Creation ---------- */
+
+/* add a new gp-frame to the given layer */
+bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
+{
+ bGPDframe *gpf, *gf;
+ short state=0;
+
+ /* error checking */
+ if ((gpl == NULL) || (cframe <= 0))
+ return NULL;
+
+ /* allocate memory for this frame */
+ gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ gpf->framenum= cframe;
+
+ /* find appropriate place to add frame */
+ if (gpl->frames.first) {
+ for (gf= gpl->frames.first; gf; gf= gf->next) {
+ /* check if frame matches one that is supposed to be added */
+ if (gf->framenum == cframe) {
+ state= -1;
+ break;
+ }
+
+ /* if current frame has already exceeded the frame to add, add before */
+ if (gf->framenum > cframe) {
+ BLI_insertlinkbefore(&gpl->frames, gf, gpf);
+ state= 1;
+ break;
+ }
+ }
+ }
+
+ /* check whether frame was added successfully */
+ if (state == -1) {
+ MEM_freeN(gpf);
+ printf("Error: frame (%d) existed already for this layer \n", cframe);
+ }
+ else if (state == 0) {
+ /* add to end then! */
+ BLI_addtail(&gpl->frames, gpf);
+ }
+
+ /* return frame */
+ return gpf;
+}
+
+/* add a new gp-layer and make it the active layer */
+bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+
+ /* check that list is ok */
+ if (gpd == NULL)
+ return NULL;
+
+ /* allocate memory for frame and add to end of list */
+ gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
+
+ /* add to datablock */
+ BLI_addtail(&gpd->layers, gpl);
+
+ /* set basic settings */
+ gpl->color[3]= 1.0f;
+ gpl->thickness = 1;
+
+ /* auto-name */
+ sprintf(gpl->info, "GP_Layer");
+ BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
+
+ /* make this one the active one */
+ gpencil_layer_setactive(gpd, gpl);
+
+ /* return layer */
+ return gpl;
+}
+
+/* add a new gp-datablock */
+bGPdata *gpencil_data_addnew (void)
+{
+ bGPdata *gpd;
+
+ /* allocate memory for a new block */
+ gpd= MEM_callocN(sizeof(bGPdata), "GreasePencilData");
+
+ /* initial settings */
+ /* it is quite useful to be able to see this info, so on by default */
+ gpd->flag = GP_DATA_DISPINFO;
+
+ return gpd;
+}
+
+/* -------- Data Duplication ---------- */
+
+/* make a copy of a given gpencil datablock */
+bGPdata *gpencil_data_duplicate (bGPdata *src)
+{
+ bGPdata *dst;
+ bGPDlayer *gpld, *gpls;
+ bGPDframe *gpfd, *gpfs;
+ bGPDstroke *gps;
+
+ /* error checking */
+ if (src == NULL)
+ return NULL;
+
+ /* make a copy of the base-data */
+ dst= MEM_dupallocN(src);
+
+ /* copy layers */
+ duplicatelist(&dst->layers, &src->layers);
+
+ for (gpld=dst->layers.first, gpls=src->layers.first; gpld && gpls;
+ gpld=gpld->next, gpls=gpls->next)
+ {
+ /* copy frames */
+ duplicatelist(&gpld->frames, &gpls->frames);
+
+ for (gpfd=gpld->frames.first, gpfs=gpls->frames.first; gpfd && gpfs;
+ gpfd=gpfd->next, gpfs=gpfs->next)
+ {
+ /* copy strokes */
+ duplicatelist(&gpfd->strokes, &gpfs->strokes);
+
+ for (gps= gpfd->strokes.first; gps; gps= gps->next)
+ {
+ gps->points= MEM_dupallocN(gps->points);
+ }
+ }
+ }
+
+ /* return new */
+ return dst;
+}
+
+/* ----------- GP-Datablock API ------------- */
+
+/* get the appropriate bGPdata from the active/given context */
+bGPdata *gpencil_data_getactive (ScrArea *sa)
+{
+ /* error checking */
+ if ((sa == NULL) && (curarea == NULL))
+ return NULL;
+ if (sa == NULL)
+ sa= curarea;
+
+ /* handle depending on spacetype */
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d= sa->spacedata.first;
+ return v3d->gpd;
+ }
+ break;
+ case SPACE_NODE:
+ {
+ SpaceNode *snode= sa->spacedata.first;
+ return snode->gpd;
+ }
+ break;
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq= sa->spacedata.first;
+
+ /* only applicable for "Image Preview" mode */
+ if (sseq->mainb)
+ return sseq->gpd;
+ }
+ break;
+ }
+
+ /* nothing found */
+ return NULL;
+}
+
+/* set bGPdata for the active/given context, and return success/fail */
+short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
+{
+ /* error checking */
+ if ((sa == NULL) && (curarea == NULL))
+ return 0;
+ if (gpd == NULL)
+ return 0;
+ if (sa == NULL)
+ sa= curarea;
+
+ /* handle depending on spacetype */
+ // TODO: someday we should have multi-user data, so no need to loose old data
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d= sa->spacedata.first;
+
+ /* free the existing block */
+ if (v3d->gpd)
+ free_gpencil_data(v3d->gpd);
+ v3d->gpd= gpd;
+
+ return 1;
+ }
+ break;
+ case SPACE_NODE:
+ {
+ SpaceNode *snode= sa->spacedata.first;
+
+ /* free the existing block */
+ if (snode->gpd)
+ free_gpencil_data(snode->gpd);
+ snode->gpd= gpd;
+
+ /* set special settings */
+ gpd->flag |= GP_DATA_VIEWALIGN;
+
+ return 1;
+ }
+ break;
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq= sa->spacedata.first;
+
+ /* only applicable if right mode */
+ if (sseq->mainb) {
+ /* free the existing block */
+ if (sseq->gpd)
+ free_gpencil_data(sseq->gpd);
+ sseq->gpd= gpd;
+
+ return 1;
+ }
+ }
+ break;
+ }
+
+ /* failed to add */
+ return 0;
+}
+
+/* Find gp-data destined for editing in animation editor (for editing time) */
+bGPdata *gpencil_data_getetime (bScreen *sc)
+{
+ bGPdata *gpd= NULL;
+ ScrArea *sa;
+
+ /* error checking */
+ if (sc == NULL)
+ return NULL;
+
+ /* search through areas, checking if an appropriate gp-block is available
+ * (this assumes that only one will have the active flag set)
+ */
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ /* handle depending on space type */
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3d-view */
+ {
+ View3D *v3d= sa->spacedata.first;
+ gpd= v3d->gpd;
+ }
+ break;
+ case SPACE_NODE: /* Node Editor */
+ {
+ SpaceNode *snode= sa->spacedata.first;
+ gpd= snode->gpd;
+ }
+ break;
+ case SPACE_SEQ: /* Sequence Editor - Image Preview */
+ {
+ SpaceSeq *sseq= sa->spacedata.first;
+
+ if (sseq->mainb)
+ gpd= sseq->gpd;
+ else
+ gpd= NULL;
+ }
+ break;
+
+ default: /* unsupported space-type */
+ gpd= NULL;
+ break;
+ }
+
+ /* check if ok */
+ if ((gpd) && (gpd->flag & GP_DATA_EDITTIME))
+ return gpd;
+ }
+
+ /* didn't find a match */
+ return NULL;
+}
+
+/* make sure only the specified view can have gp-data for time editing
+ * - gpd can be NULL, if we wish to make sure no gp-data is being edited
+ */
+void gpencil_data_setetime (bScreen *sc, bGPdata *gpd)
+{
+ bGPdata *gpdn= NULL;
+ ScrArea *sa;
+
+ /* error checking */
+ if (sc == NULL)
+ return;
+
+ /* search through areas, checking if an appropriate gp-block is available
+ * (this assumes that only one will have the active flag set)
+ */
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ /* handle depending on space type */
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3d-view */
+ {
+ View3D *v3d= sa->spacedata.first;
+ gpdn= v3d->gpd;
+ }
+ break;
+ case SPACE_NODE: /* Node Editor */
+ {
+ SpaceNode *snode= sa->spacedata.first;
+ gpdn= snode->gpd;
+ }
+ break;
+ case SPACE_SEQ: /* Sequence Editor - Image Preview */
+ {
+ SpaceSeq *sseq= sa->spacedata.first;
+ gpdn= sseq->gpd;
+ }
+ break;
+
+ default: /* unsupported space-type */
+ gpdn= NULL;
+ break;
+ }
+
+ /* clear flag if a gp-data block found */
+ if (gpdn)
+ gpdn->flag &= ~GP_DATA_EDITTIME;
+ }
+
+ /* set active flag for this block (if it is provided) */
+ if (gpd)
+ gpd->flag |= GP_DATA_EDITTIME;
+}
+
+/* -------- GP-Frame API ---------- */
+
+/* delete the last stroke of the given frame */
+void gpencil_frame_delete_laststroke (bGPDframe *gpf)
+{
+ bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
+
+ /* error checking */
+ if (ELEM(NULL, gpf, gps))
+ return;
+
+ /* free the stroke and its data */
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
+}
+
+/* -------- GP-Layer API ---------- */
+
+/* get the appropriate gp-frame from a given layer
+ * - this sets the layer's actframe var (if allowed to)
+ * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
+ */
+bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
+{
+ bGPDframe *gpf = NULL;
+ short found = 0;
+
+ /* error checking */
+ if (gpl == NULL) return NULL;
+ if (cframe <= 0) cframe = 1;
+
+ /* check if there is already an active frame */
+ if (gpl->actframe) {
+ gpf= gpl->actframe;
+
+ /* do not allow any changes to layer's active frame if layer is locked */
+ if (gpl->flag & GP_LAYER_LOCKED)
+ return gpf;
+ /* do not allow any changes to actframe if frame has painting tag attached to it */
+ if (gpf->flag & GP_FRAME_PAINT)
+ return gpf;
+
+ /* try to find matching frame */
+ if (gpf->framenum < cframe) {
+ for (; gpf; gpf= gpf->next) {
+ if (gpf->framenum == cframe) {
+ found= 1;
+ break;
+ }
+ else if ((gpf->next) && (gpf->next->framenum > cframe)) {
+ found= 1;
+ break;
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe= gpf;
+ else
+ gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe= gpf;
+ else
+ gpl->actframe= gpl->frames.last;
+ }
+ else {
+ for (; gpf; gpf= gpf->prev) {
+ if (gpf->framenum <= cframe) {
+ found= 1;
+ break;
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe= gpf;
+ else
+ gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe= gpf;
+ else
+ gpl->actframe= gpl->frames.first;
+ }
+ }
+ else if (gpl->frames.first) {
+ /* check which of the ends to start checking from */
+ const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
+ const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
+
+ if (abs(cframe-first) > abs(cframe-last)) {
+ /* find gp-frame which is less than or equal to cframe */
+ for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
+ if (gpf->framenum <= cframe) {
+ found= 1;
+ break;
+ }
+ }
+ }
+ else {
+ /* find gp-frame which is less than or equal to cframe */
+ for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+ if (gpf->framenum <= cframe) {
+ found= 1;
+ break;
+ }
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe= gpf;
+ else
+ gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe= gpf;
+ else {
+ /* unresolved errogenous situation! */
+ printf("Error: cannot find appropriate gp-frame \n");
+ }
+ }
+ else {
+ /* currently no frames (add if allowed to) */
+ if (addnew)
+ gpl->actframe= gpencil_frame_addnew(gpl, cframe);
+ else {
+ /* don't do anything... this may be when no frames yet! */
+ }
+ }
+
+ /* return */
+ return gpl->actframe;
+}
+
+/* delete the given frame from a layer */
+void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
+{
+ /* error checking */
+ if (ELEM(NULL, gpl, gpf))
+ return;
+
+ /* free the frame and its data */
+ free_gpencil_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ gpl->actframe = NULL;
+}
+
+/* get the active gp-layer for editing */
+bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->layers.first))
+ return NULL;
+
+ /* loop over layers until found (assume only one active) */
+ for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ return gpl;
+ }
+
+ /* no active layer found */
+ return NULL;
+}
+
+/* set the active gp-layer */
+void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
+{
+ bGPDlayer *gpl;
+
+ /* error checking */
+ if (ELEM3(NULL, gpd, gpd->layers.first, active))
+ return;
+
+ /* loop over layers deactivating all */
+ for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
+ gpl->flag &= ~GP_LAYER_ACTIVE;
+
+ /* set as active one */
+ active->flag |= GP_LAYER_ACTIVE;
+}
+
+/* delete the active gp-layer */
+void gpencil_layer_delactive (bGPdata *gpd)
+{
+ bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl))
+ return;
+
+ /* free layer */
+ free_gpencil_frames(gpl);
+ BLI_freelinkN(&gpd->layers, gpl);
+
+}
+
+/* ************************************************** */
+/* GREASE-PENCIL EDITING MODE - Tools */
+
+/* --------- Data Deletion ---------- */
+
+/* delete the last stroke on the active layer */
+void gpencil_delete_laststroke (bGPdata *gpd)
+{
+ bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+ bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+
+ gpencil_frame_delete_laststroke(gpf);
+}
+
+/* delete the active frame */
+void gpencil_delete_actframe (bGPdata *gpd)
+{
+ bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+ bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+
+ gpencil_layer_delframe(gpl, gpf);
+}
+
+
+
+/* delete various grase-pencil elements
+ * mode: 1 - last stroke
+ * 2 - active frame
+ * 3 - active layer
+ */
+void gpencil_delete_operation (short mode) // unused
+{
+ bGPdata *gpd;
+
+ /* get datablock to work on */
+ gpd= gpencil_data_getactive(NULL);
+ if (gpd == NULL) return;
+
+ switch (mode) {
+ case 1: /* last stroke */
+ gpencil_delete_laststroke(gpd);
+ break;
+ case 2: /* active frame */
+ gpencil_delete_actframe(gpd);
+ break;
+ case 3: /* active layer */
+ gpencil_layer_delactive(gpd);
+ break;
+ }
+
+ /* redraw and undo-push */
+ BIF_undo_push("GPencil Delete");
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/* display a menu for deleting different grease-pencil elements */
+void gpencil_delete_menu (void) // unused
+{
+ short mode;
+
+ mode= pupmenu("Erase...%t|Last Stroke%x1|Active Frame%x2|Active Layer%x3");
+ if (mode <= 0) return;
+
+ gpencil_delete_operation(mode);
+}
+
+/* ************************************************** */
+/* GREASE-PENCIL EDITING MODE - Painting */
+
+/* ---------- 'Globals' and Defines ----------------- */
+
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX 500
+
+/* ------ */
+
+/* Temporary 'Stroke' Operation data */
+typedef struct tGPsdata {
+ ScrArea *sa; /* area where painting originated */
+ View2D *v2d; /* needed for GP_STROKE_2DSPACE */
+
+ bGPdata *gpd; /* gp-datablock layer comes from */
+ bGPDlayer *gpl; /* layer we're working on */
+ bGPDframe *gpf; /* frame we're working on */
+
+ short status; /* current status of painting */
+ short paintmode; /* mode for painting (L_MOUSE or R_MOUSE for now) */
+} tGPsdata;
+
+/* values for tGPsdata->status */
+enum {
+ GP_STATUS_NORMAL = 0, /* running normally */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE /* painting done */
+};
+
+/* Return flags for adding points to stroke buffer */
+enum {
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL /* cannot add any more points to buffer */
+};
+
+/* ---------- Stroke Editing ------------ */
+
+/* clear the session buffers (call this before AND after a paint operation) */
+static void gp_session_validatebuffer (tGPsdata *p)
+{
+ bGPdata *gpd= p->gpd;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->sbuffer)
+ memset(gpd->sbuffer, 0, sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX);
+ else
+ gpd->sbuffer= MEM_callocN(sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+
+ /* reset indices */
+ gpd->sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->sbuffer_sflag= 0;
+}
+
+/* init new painting session */
+static void gp_session_initpaint (tGPsdata *p)
+{
+ /* clear previous data (note: is on stack) */
+ memset(p, 0, sizeof(tGPsdata));
+
+ /* make sure the active view (at the starting time) is a 3d-view */
+ if (curarea == NULL) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: No active view for painting \n");
+ return;
+ }
+ switch (curarea->spacetype) {
+ /* supported views first */
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d= curarea->spacedata.first;
+
+ /* set current area */
+ p->sa= curarea;
+
+ /* check that gpencil data is allowed to be drawn */
+ if ((v3d->flag2 & V3D_DISPGP)==0) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: In active view, Grease Pencil not shown \n");
+ return;
+ }
+ }
+ break;
+ case SPACE_NODE:
+ {
+ SpaceNode *snode= curarea->spacedata.first;
+
+ /* set current area */
+ p->sa= curarea;
+ p->v2d= &snode->v2d;
+
+ /* check that gpencil data is allowed to be drawn */
+ if ((snode->flag & SNODE_DISPGP)==0) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: In active view, Grease Pencil not shown \n");
+ return;
+ }
+ }
+ break;
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq= curarea->spacedata.first;
+
+ /* set current area */
+ p->sa= curarea;
+ p->v2d= &sseq->v2d;
+
+ /* check that gpencil data is allowed to be drawn */
+ if (sseq->mainb == 0) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil \n");
+ return;
+ }
+ if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: In active view, Grease Pencil not shown \n");
+ return;
+ }
+ }
+ break;
+ /* unsupported views */
+ default:
+ {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: Active view not appropriate for Grease Pencil drawing \n");
+ return;
+ }
+ break;
+ }
+
+ /* get gp-data */
+ p->gpd= gpencil_data_getactive(p->sa);
+ if (p->gpd == NULL) {
+ short ok;
+
+ p->gpd= gpencil_data_addnew();
+ ok= gpencil_data_setactive(p->sa, p->gpd);
+
+ /* most of the time, the following check isn't needed */
+ if (ok == 0) {
+ /* free gpencil data as it can't be used */
+ free_gpencil_data(p->gpd);
+ p->gpd= NULL;
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: Could not assign newly created Grease Pencil data to active area \n");
+ return;
+ }
+ }
+
+ /* set edit flags */
+ G.f |= G_GREASEPENCIL;
+
+ /* clear out buffer (stored in gp-data) in case something contaminated it */
+ gp_session_validatebuffer(p);
+}
+
+/* cleanup after a painting session */
+static void gp_session_cleanup (tGPsdata *p)
+{
+ bGPdata *gpd= p->gpd;
+
+ /* error checking */
+ if (gpd == NULL)
+ return;
+
+ /* free stroke buffer */
+ if (gpd->sbuffer) {
+ MEM_freeN(gpd->sbuffer);
+ gpd->sbuffer= NULL;
+ }
+
+ /* clear flags */
+ gpd->sbuffer_size= 0;
+ gpd->sbuffer_sflag= 0;
+}
+
+/* convert screen-coordinates to buffer-coordinates */
+static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
+{
+ bGPdata *gpd= p->gpd;
+
+ /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+ if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
+ short mx=mval[0], my=mval[1];
+ float *fp= give_cursor();
+ float dvec[3];
+
+ /* method taken from editview.c - mouse_cursor() */
+ project_short_noclip(fp, mval);
+ window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+ VecSubf(out, fp, dvec);
+ }
+
+ /* 2d - on 'canvas' (assume that p->v2d is set) */
+ else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
+ float x, y;
+
+ areamouseco_to_ipoco(p->v2d, mval, &x, &y);
+
+ out[0]= x;
+ out[1]= y;
+ }
+
+ /* 2d - relative to screen (viewport area) */
+ else {
+ out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000;
+ out[1] = (float)(mval[1]) / (float)(p->sa->winy) * 1000;
+ }
+}
+
+/* add current stroke-point to buffer (returns whether point was successfully added) */
+static short gp_stroke_addpoint (tGPsdata *p, short mval[], float pressure)
+{
+ bGPdata *gpd= p->gpd;
+ bGPDspoint *pt;
+
+ /* check if still room in buffer */
+ if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_OVERFLOW;
+
+
+ /* get pointer to destination point */
+ pt= gpd->sbuffer + gpd->sbuffer_size;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, mval, &pt->x);
+
+ /* store other settings */
+ pt->pressure= pressure;
+
+ /* increment counters */
+ gpd->sbuffer_size++;
+
+ /* check if another operation can still occur */
+ if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_FULL;
+ else
+ return GP_STROKEADD_NORMAL;
+}
+
+/* smooth a stroke (in buffer) before storing it */
+static void gp_stroke_smooth (tGPsdata *p)
+{
+ bGPdata *gpd= p->gpd;
+ int i=0, cmx=gpd->sbuffer_size;
+
+ /* don't try if less than 2 points in buffer */
+ if ((cmx <= 2) || (gpd->sbuffer == NULL))
+ return;
+
+ /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
+ for (i=0; i < gpd->sbuffer_size; i++) {
+ bGPDspoint *pc= (gpd->sbuffer + i);
+ bGPDspoint *pb= (i-1 > 0)?(pc-1):(pc);
+ bGPDspoint *pa= (i-2 > 0)?(pc-2):(pb);
+ bGPDspoint *pd= (i+1 < cmx)?(pc+1):(pc);
+ bGPDspoint *pe= (i+2 < cmx)?(pc+2):(pd);
+
+ pc->x= (0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
+ pc->y= (0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
+ }
+}
+
+/* make a new stroke from the buffer data */
+static void gp_stroke_newfrombuffer (tGPsdata *p)
+{
+ bGPdata *gpd= p->gpd;
+ bGPDstroke *gps;
+ bGPDspoint *pt, *ptc;
+ int i, totelem;
+
+ /* get total number of points to allocate space for */
+ totelem = gpd->sbuffer_size;
+
+ /* exit with error if no valid points from this stroke */
+ if (totelem == 0) {
+ if (G.f & G_DEBUG)
+ printf("Error: No valid points in stroke buffer to convert (tot=%d) \n", gpd->sbuffer_size);
+ return;
+ }
+
+ /* allocate memory for a new stroke */
+ gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+
+ /* allocate enough memory for a continuous array for storage points */
+ pt= gps->points= MEM_callocN(sizeof(bGPDspoint)*totelem, "gp_stroke_points");
+
+ /* copy appropriate settings for stroke */
+ gps->totpoints= totelem;
+ gps->thickness= p->gpl->thickness;
+ gps->flag= gpd->sbuffer_sflag;
+
+ /* copy points from the buffer to the stroke */
+ for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
+ memcpy(pt, ptc, sizeof(bGPDspoint));
+ pt++;
+ }
+
+ /* add stroke to frame */
+ BLI_addtail(&p->gpf->strokes, gps);
+}
+
+/* ---------- 'Paint' Tool ------------ */
+
+/* init new stroke */
+static void gp_paint_initstroke (tGPsdata *p)
+{
+ /* get active layer (or add a new one if non-existent) */
+ p->gpl= gpencil_layer_getactive(p->gpd);
+ if (p->gpl == NULL)
+ p->gpl= gpencil_layer_addnew(p->gpd);
+ if (p->gpl->flag & GP_LAYER_LOCKED) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: Cannot paint on locked layer \n");
+ return;
+ }
+
+ /* get active frame (add a new one if not matching frame) */
+ p->gpf= gpencil_layer_getframe(p->gpl, CFRA, 1);
+ if (p->gpf == NULL) {
+ p->status= GP_STATUS_ERROR;
+ if (G.f & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init) \n");
+ return;
+ }
+ else
+ p->gpf->flag |= GP_FRAME_PAINT;
+
+ /* check if points will need to be made in 3d-space */
+ if (p->gpd->flag & GP_DATA_VIEWALIGN) {
+ switch (p->sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ float *fp= give_cursor();
+ initgrabz(fp[0], fp[1], fp[2]);
+
+ p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
+ }
+ break;
+ case SPACE_NODE:
+ {
+ p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
+ }
+ break;
+ case SPACE_SEQ:
+ {
+ /* for now, this is not applicable here... */
+ }
+ break;
+ }
+ }
+}
+
+/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
+static void gp_paint_strokeend (tGPsdata *p)
+{
+ /* sanitize stroke-points in buffer */
+ gp_stroke_smooth(p);
+
+ /* transfer stroke to frame */
+ gp_stroke_newfrombuffer(p);
+
+ /* clean up buffer now */
+ gp_session_validatebuffer(p);
+}
+
+/* finish off stroke painting operation */
+static void gp_paint_cleanup (tGPsdata *p)
+{
+ /* finish off a stroke */
+ gp_paint_strokeend(p);
+
+ /* "unlock" frame */
+ p->gpf->flag &= ~GP_FRAME_PAINT;
+
+ /* add undo-push so stroke can be undone */
+ /* FIXME: currently disabled, as it's impossible to get this working nice
+ * as gpenci data is on currently screen-level (which isn't saved to undo files)
+ */
+ //BIF_undo_push("GPencil Stroke");
+
+ /* force redraw after drawing action */
+ force_draw(0);
+}
+
+/* -------- */
+
+/* main call to paint a new stroke */
+short gpencil_paint (short mousebutton)
+{
+ tGPsdata p;
+ short prevmval[2], mval[2];
+ float opressure, pressure;
+ short ok = GP_STROKEADD_NORMAL;
+
+ /* init paint-data */
+ gp_session_initpaint(&p);
+ if (p.status == GP_STATUS_ERROR) {
+ gp_session_cleanup(&p);
+ return 0;
+ }
+ gp_paint_initstroke(&p);
+ if (p.status == GP_STATUS_ERROR) {
+ gp_session_cleanup(&p);
+ return 0;
+ }
+
+ /* set cursor to indicate drawing */
+ setcursor_space(p.sa->spacetype, CURSOR_VPAINT);
+
+ /* init drawing-device settings */
+ getmouseco_areawin(mval);
+ pressure = get_pressure();
+
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ opressure= pressure;
+
+ /* only allow painting of single 'dots' if:
+ * - pressure is not excessive (as it can be on some windows tablets)
+ * - draw-mode for active datablock is turned on
+ */
+ if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) {
+ gp_stroke_addpoint(&p, mval, pressure);
+ }
+
+ /* paint loop */
+ do {
+ /* get current user input */
+ getmouseco_areawin(mval);
+ pressure = get_pressure();
+
+ /* only add current point to buffer if mouse moved (otherwise wait until it does) */
+ if ((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+ /* try to add point */
+ ok= gp_stroke_addpoint(&p, mval, pressure);
+
+ /* handle errors while adding point */
+ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+ /* finish off old stroke */
+ gp_paint_strokeend(&p);
+
+ /* start a new stroke, starting from previous point */
+ gp_stroke_addpoint(&p, prevmval, opressure);
+ ok= gp_stroke_addpoint(&p, mval, pressure);
+ }
+ else if (ok == GP_STROKEADD_INVALID) {
+ /* the painting operation cannot continue... */
+ error("Cannot paint stroke");
+ p.status = GP_STATUS_ERROR;
+
+ if (G.f & G_DEBUG)
+ printf("Error: Grease-Pencil Paint - Add Point Invalid \n");
+ break;
+ }
+ force_draw(0);
+
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ opressure= pressure;
+ }
+ else
+ BIF_wait_for_statechange();
+
+ /* do mouse checking at the end, so don't check twice, and potentially
+ * miss a short tap
+ */
+ } while (get_mbut() & mousebutton);
+
+ /* clear edit flags */
+ G.f &= ~G_GREASEPENCIL;
+
+ /* restore cursor to indicate end of drawing */
+ setcursor_space(p.sa->spacetype, CURSOR_STD);
+
+ /* check size of buffer before cleanup, to determine if anything happened here */
+ ok= p.gpd->sbuffer_size;
+
+ /* cleanup */
+ gp_paint_cleanup(&p);
+ gp_session_cleanup(&p);
+
+ /* done! return if a stroke was successfully added */
+ return ok;
+}
+
+
+/* All event (loops) handling checking if stroke drawing should be initiated
+ * should call this function.
+ */
+short gpencil_do_paint (ScrArea *sa)
+{
+ bGPdata *gpd = gpencil_data_getactive(sa);
+ short mousebutton = L_MOUSE; /* for now, this is always on L_MOUSE*/
+ short retval= 0;
+
+ /* check if possible to do painting */
+ if (gpd == NULL)
+ return 0;
+
+ /* currently, we will only paint if:
+ * 1. draw-mode on gpd is set (for accessibility reasons)
+ * (single 'dots' are only available via this method)
+ * 2. if shift-modifier is held + lmb -> 'quick paint'
+ */
+ if (gpd->flag & GP_DATA_EDITPAINT) {
+ /* try to paint */
+ retval = gpencil_paint(mousebutton);
+ }
+ else if (G.qual == LR_SHIFTKEY) {
+ /* try to paint */
+ retval = gpencil_paint(mousebutton);
+ }
+
+ /* return result of trying to paint */
+ return retval;
+}
+
+/* ************************************************** */
diff --git a/source/blender/src/header_action.c b/source/blender/src/header_action.c
index 9c7046c5111..50d343ca470 100644
--- a/source/blender/src/header_action.c
+++ b/source/blender/src/header_action.c
@@ -50,8 +50,11 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
#include "BIF_editaction.h"
#include "BIF_interface.h"
+#include "BIF_language.h"
#include "BIF_poseobject.h"
#include "BIF_resources.h"
#include "BIF_screen.h"
@@ -76,6 +79,7 @@
#include "blendef.h"
#include "mydevice.h"
+/* ------------------------------- */
/* enums declaring constants that are used as menu event codes */
enum {
@@ -212,6 +216,16 @@ enum {
ACTMENU_MARKERS_LOCALMOVE
};
+/* ------------------------------- */
+/* macros for easier state testing (only for use here) */
+
+/* test if active action editor is showing any markers */
+#define G_SACTION_HASMARKERS \
+ ((G.saction->action && G.saction->action->markers.first) \
+ || (G.scene->markers.first))
+
+/* ------------------------------- */
+
void do_action_buttons(unsigned short event)
{
Object *ob= OBACT;
@@ -398,32 +412,41 @@ static uiBlock *action_viewmenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
- "Show Sliders|", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1,
- ACTMENU_VIEW_SLIDERS, "");
-
- uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOHIDE)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
- "Show Hidden Channels|", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1,
- ACTMENU_VIEW_NOHIDE, "");
-
- uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NODRAWGCOLORS)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
- "Use Group Colors|", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1,
- ACTMENU_VIEW_GCOLORS, "");
-
- // this option may get removed in future
- uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
- "Cull Out-of-View Keys (Time)|", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1,
- ACTMENU_VIEW_HORIZOPTIMISE, "");
+ if (G.saction->mode == SACTCONT_GPENCIL) {
+ // this option may get removed in future
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Cull Out-of-View Keys (Time)|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_HORIZOPTIMISE, "");
+ }
+ else {
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Show Sliders|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_SLIDERS, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOHIDE)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Show Hidden Channels|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_NOHIDE, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NODRAWGCOLORS)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
+ "Use Group Colors|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_GCOLORS, "");
+
+ // this option may get removed in future
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_HORIZOPTIMISEON)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Cull Out-of-View Keys (Time)|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_HORIZOPTIMISE, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOTRANSKEYCULL)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
+ "AutoMerge Keyframes|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_TRANSDELDUPS, "");
+ }
- uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_NOTRANSKEYCULL)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
- "AutoMerge Keyframes|", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1,
- ACTMENU_VIEW_TRANSDELDUPS, "");
-
uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
"Lock Time to Other Windows|", 0, yco-=20,
@@ -476,7 +499,7 @@ static uiBlock *action_viewmenu(void *arg_unused)
menuwidth, 19, NULL, 0.0, 0.0, 1,
ACTMENU_VIEW_PREVRANGECLEAR, "");
- if (G.saction->action) {
+ if ((G.saction->mode == SACTCONT_ACTION) && (G.saction->action)) {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Preview Range from Action Length|Ctrl Alt P", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1,
@@ -550,13 +573,15 @@ static uiBlock *action_selectmenu_columnmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"On Current Frame|Ctrl K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_SEL_COLUMN_CFRA, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "On Selected Markers|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_COLUMN_MARKERSCOLUMN, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Between Selected Markers|Alt K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_COLUMN_MARKERSBETWEEN, "");
+ if (G_SACTION_HASMARKERS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "On Selected Markers|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_COLUMN_MARKERSCOLUMN, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Between Selected Markers|Alt K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_COLUMN_MARKERSBETWEEN, "");
+ }
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60);
@@ -659,14 +684,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
"Border Select Keys|B", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_SEL_BORDER, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Border Select Channels|B", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_BORDERC, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Border Select Markers|Ctrl B", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_BORDERM, "");
+ if (G_SACTION_HASMARKERS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Border Select Markers|Ctrl B", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_BORDERM, "");
+ }
+ if (G.saction->mode != SACTCONT_SHAPEKEY) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Border Select Channels|B", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_BORDERC, "");
+ }
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -675,14 +704,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
"Select/Deselect All Keys|A", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_SEL_ALL_KEYS, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Select/Deselect All Markers|Ctrl A", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_ALL_MARKERS, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Select/Deselect All Channels|A", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_ALL_CHAN, "");
+ if (G_SACTION_HASMARKERS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Select/Deselect All Markers|Ctrl A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_ALL_MARKERS, "");
+ }
+ if (G.saction->mode != SACTCONT_SHAPEKEY) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Select/Deselect All Channels|A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_ALL_CHAN, "");
+ }
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -691,14 +724,18 @@ static uiBlock *action_selectmenu(void *arg_unused)
"Inverse Keys|Ctrl I", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_SEL_INVERSE_KEYS, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Inverse Markers|Ctrl Shift I", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_INVERSE_MARKERS, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
- "Inverse All Channels|Ctrl I", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 0,
- ACTMENU_SEL_INVERSE_CHANNELS, "");
+ if (G_SACTION_HASMARKERS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Inverse Markers|Ctrl Shift I", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_INVERSE_MARKERS, "");
+ }
+ if (G.saction->mode != SACTCONT_SHAPEKEY) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Inverse All Channels|Ctrl I", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_INVERSE_CHANNELS, "");
+ }
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -971,6 +1008,40 @@ static uiBlock *action_channelmenu(void *arg_unused)
return block;
}
+/* note: uses do_action_channelmenu too... */
+static uiBlock *action_gplayermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_gplayermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_channelmenu, NULL);
+
+ uiDefIconTextBlockBut(block, action_channelmenu_settingsmenu,
+ NULL, ICON_RIGHTARROW_THIN,
+ "Settings", 0, yco-=20, 120, 20, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Delete|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_CHANNELS_DELETE, "");
+
+ if (curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
static void do_action_keymenu_transformmenu(void *arg, int event)
{
switch (event)
@@ -1400,6 +1471,51 @@ static uiBlock *action_keymenu(void *arg_unused)
return block;
}
+/* note: uses do_action_keymenu too! */
+static uiBlock *action_framemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_framemenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_keymenu, NULL);
+
+ uiDefIconTextBlockBut(block, action_keymenu_transformmenu,
+ NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 20, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_snapmenu,
+ NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 20, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_mirrormenu,
+ NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 20, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Duplicate|Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_DUPLICATE, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Delete|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_DELETE, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
static void do_action_markermenu(void *arg, int event)
{
switch(event)
@@ -1461,17 +1577,19 @@ static uiBlock *action_markermenu(void *arg_unused)
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_NAME, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_MOVE, "");
-
- uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
-
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Pose Marker|Shift L", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALADD, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Pose Marker|Ctrl Shift L", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALRENAME, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Pose Marker|Alt L", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALDELETE, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Pose Marker|Ctrl L", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALMOVE, "");
+
+ if (G.saction->mode == SACTCONT_ACTION) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Pose Marker|Shift L", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALADD, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Pose Marker|Ctrl Shift L", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALRENAME, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Pose Marker|Alt L", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALDELETE, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Pose Marker|Ctrl L", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALMOVE, "");
+ }
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
@@ -1498,6 +1616,7 @@ void action_buttons(void)
return;
/* copied from drawactionspace.... */
+ // FIXME: do for gpencil too?
if (!G.saction->pin) {
if (OBACT)
G.saction->action = OBACT->action;
@@ -1558,68 +1677,112 @@ void action_buttons(void)
"Select", xco, -2, xmax-3, 24, "");
xco+= xmax;
- if (G.saction->action) {
+ if ((G.saction->action) && (G.saction->mode==SACTCONT_ACTION)) {
xmax= GetButStringLength("Channel");
uiDefPulldownBut(block, action_channelmenu, NULL,
"Channel", xco, -2, xmax-3, 24, "");
xco+= xmax;
}
+ else if ((G.saction->gpd) && (G.saction->mode==SACTCONT_GPENCIL)) {
+ xmax= GetButStringLength("Channel");
+ uiDefPulldownBut(block, action_gplayermenu, NULL,
+ "Channel", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
xmax= GetButStringLength("Marker");
uiDefPulldownBut(block, action_markermenu, NULL,
"Marker", xco, -2, xmax-3, 24, "");
xco+= xmax;
- xmax= GetButStringLength("Key");
- uiDefPulldownBut(block, action_keymenu, NULL,
- "Key", xco, -2, xmax-3, 24, "");
- xco+= xmax;
+ if (G.saction->mode == SACTCONT_GPENCIL) {
+ xmax= GetButStringLength("Frame");
+ uiDefPulldownBut(block, action_framemenu, NULL,
+ "Frame", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ }
+ else {
+ xmax= GetButStringLength("Key");
+ uiDefPulldownBut(block, action_keymenu, NULL,
+ "Key", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
}
uiBlockSetEmboss(block, UI_EMBOSS);
- /* NAME ETC */
- ob= OBACT;
- from = (ID *)ob;
-
- xco= std_libbuttons(block, xco, 0, B_ACTPIN, &G.saction->pin,
- B_ACTIONBROWSE, ID_AC, 0, (ID*)G.saction->action,
- from, &(G.saction->actnr), B_ACTALONE,
- B_ACTLOCAL, B_ACTIONDELETE, 0, B_KEEPDATA);
+ /* MODE SELECTOR */
+ uiDefButC(block, MENU, B_REDR,
+ "Editor Mode %t|Action Editor %x0|ShapeKey Editor %x1|Grease Pencil %x2",
+ xco,0,90,YIC, &(G.saction->mode), 0, 1, 0, 0,
+ "Editing modes for this editor");
- uiClearButLock();
-
- xco += 8;
- /* COPY PASTE */
- uiBlockBeginAlign(block);
- if (curarea->headertype==HEADERTOP) {
- uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
- uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
- }
- else {
- uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
- uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
- }
- uiBlockEndAlign(block);
- xco += (XIC + 8);
+ xco += (90 + 8);
- /* draw AUTOSNAP */
- if (G.saction->flag & SACTION_DRAWTIME) {
- uiDefButS(block, MENU, B_REDR,
- "Auto-Snap Keyframes %t|No Snap %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3",
- xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
- "Auto-snapping mode for keyframes when transforming");
+ /* MODE-DEPENDENT DRAWING */
+ if (G.saction->mode == SACTCONT_GPENCIL) {
+ char gp_name[64];
+
+ /* pin button */
+ uiDefIconButS(block, ICONTOG, B_ACTPIN, ICON_PIN_DEHLT, xco,0,XIC,YIC, &G.saction->pin, 0, 0, 0, 0, "Keeps this view displaying the current data regardless of what Grease Pencil set is active");
+ xco += (XIC + 5);
+
+ /* just a simple string to help identify if any content */
+ glRasterPos2f((float)xco, 5.0);
+ BIF_RasterPos((float)xco, 5.0); // stupid texture fonts
+ BIF_ThemeColor(TH_TEXT);
+
+ sprintf(gp_name, (G.saction->gpd)?"Grease Pencil Data":"<None>");
+ xmax= GetButStringLength(gp_name);
+ BIF_DrawString(uiBlockGetCurFont(block), gp_name, (U.transopts & USER_TR_BUTTONS));
+ xco += xmax;
}
else {
- uiDefButS(block, MENU, B_REDR,
- "Auto-Snap Keyframes %t|No Snap %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3",
- xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
- "Auto-snapping mode for keyframes when transforming");
+ /* NAME ETC */
+ ob= OBACT;
+ from = (ID *)ob;
+
+ xco= std_libbuttons(block, xco, 0, B_ACTPIN, &G.saction->pin,
+ B_ACTIONBROWSE, ID_AC, 0, (ID*)G.saction->action,
+ from, &(G.saction->actnr), B_ACTALONE,
+ B_ACTLOCAL, B_ACTIONDELETE, 0, B_KEEPDATA);
+
+ uiClearButLock();
+
+ xco += 8;
+
+ /* COPY PASTE */
+ uiBlockBeginAlign(block);
+ if (curarea->headertype==HEADERTOP) {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ else {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ uiBlockEndAlign(block);
+ xco += (XIC + 8);
+
+ /* draw AUTOSNAP */
+ if (G.saction->flag & SACTION_DRAWTIME) {
+ uiDefButC(block, MENU, B_REDR,
+ "Auto-Snap Keyframes %t|No Snap %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for keyframes when transforming");
+ }
+ else {
+ uiDefButC(block, MENU, B_REDR,
+ "Auto-Snap Keyframes %t|No Snap %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for keyframes when transforming");
+ }
+
+ xco += (70 + 8);
}
- xco += (70 + 8);
-
/* draw LOCK */
uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco, 0, XIC, YIC,
&(G.saction->lock), 0, 0, 0, 0,
diff --git a/source/blender/src/header_node.c b/source/blender/src/header_node.c
index ec6bbc9044c..4c7b4aa80bc 100644
--- a/source/blender/src/header_node.c
+++ b/source/blender/src/header_node.c
@@ -110,12 +110,16 @@ static void do_node_viewmenu(void *arg, int event)
case 3: /* View all */
snode_home(curarea, snode);
break;
+ case 4: /* Grease Pencil */
+ add_blockhandler(curarea, NODES_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
+ break;
}
allqueue(REDRAWNODE, 0);
}
static uiBlock *node_viewmenu(void *arg_unused)
{
+ SpaceNode *snode= curarea->spacedata.first;
uiBlock *block;
short yco= 0, menuwidth=120;
@@ -123,6 +127,12 @@ static uiBlock *node_viewmenu(void *arg_unused)
UI_EMBOSSP, UI_HELV, curarea->headwin);
uiBlockSetButmFunc(block, do_node_viewmenu, NULL);
+ if (snode->nodetree) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Grease Pencil...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
diff --git a/source/blender/src/header_seq.c b/source/blender/src/header_seq.c
index 393830a61cf..e5a63b9fe45 100644
--- a/source/blender/src/header_seq.c
+++ b/source/blender/src/header_seq.c
@@ -100,6 +100,9 @@ static void do_seq_viewmenu(void *arg, int event)
case 6: /* Draw time/frames */
sseq->flag ^= SEQ_DRAWFRAMES;
break;
+ case 7: /* Grease Pencil */
+ add_blockhandler(curarea, SEQ_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
+ break;
}
}
@@ -111,7 +114,15 @@ static uiBlock *seq_viewmenu(void *arg_unused)
block= uiNewBlock(&curarea->uiblocks, "seq_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
uiBlockSetButmFunc(block, do_seq_viewmenu, NULL);
-
+
+ if (sseq->mainb) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL,
+ "Grease Pencil...", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
if (sseq->mainb == 0) {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Play Back Animation "
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index 0f3a46c8a8c..71bf0cd9bd4 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -601,6 +601,9 @@ static void do_view3d_viewmenu(void *arg, int event)
break;
case 20: /* Transform Space Panel */
add_blockhandler(curarea, VIEW3D_HANDLER_TRANSFORM, UI_PNL_UNSTOW);
+ break;
+ case 21: /* Grease Pencil */
+ add_blockhandler(curarea, VIEW3D_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
break;
}
allqueue(REDRAWVIEW3D, 1);
@@ -619,6 +622,7 @@ static uiBlock *view3d_viewmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Render Preview...|Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 18, "");
uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "View Properties...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 16, "");
uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Background Image...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Grease Pencil...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 21, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c
index 4fbf92d646e..ba8649eaa86 100644
--- a/source/blender/src/interface.c
+++ b/source/blender/src/interface.c
@@ -618,6 +618,9 @@ void uiBoundsBlock(uiBlock *block, int addval)
uiBut *bt;
int xof;
+ if(block==NULL)
+ return;
+
if(block->buttons.first==NULL) {
if(block->panel) {
block->minx= 0.0; block->maxx= block->panel->sizex;
@@ -5405,7 +5408,9 @@ uiBlock *uiNewBlock(ListBase *lb, char *name, short dt, short font, short win)
int getsizex, getsizey;
bwin_getsize(win, &getsizex, &getsizey);
- block->aspect= 2.0/( (getsizex)*block->winmat[0][0]);
+ /* TODO - investigate why block->winmat[0][0] is negative
+ * in the image view when viewRedrawForce is called */
+ block->aspect= 2.0/fabs( (getsizex)*block->winmat[0][0]);
}
uiSetCurFont(block, font);
diff --git a/source/blender/src/poselib.c b/source/blender/src/poselib.c
index 2d8b0c81175..fb2bfe5b605 100644
--- a/source/blender/src/poselib.c
+++ b/source/blender/src/poselib.c
@@ -756,6 +756,13 @@ static void poselib_keytag_pose (tPoseLib_PreviewData *pld)
*/
static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step)
{
+ /* check if we no longer have search-string, but don't have any marker */
+ if (pld->marker == NULL) {
+ if ((step) && (pld->searchstr[0] == 0))
+ pld->marker= pld->act->markers.first;
+ }
+
+ /* the following operations assume that there is a starting point and direction */
if ((pld->marker) && (step)) {
/* search-string dictates a special approach */
if (pld->searchstr[0]) {
@@ -1262,9 +1269,14 @@ void poselib_preview_poses (Object *ob, short apply_active)
/* get search-string */
index= pld.search_cursor;
- memcpy(&tempstr[0], &pld.searchstr[0], index);
- tempstr[index]= '|';
- memcpy(&tempstr[index+1], &pld.searchstr[index], 64-index);
+ if (IN_RANGE(index, 0, 64)) {
+ memcpy(&tempstr[0], &pld.searchstr[0], index);
+ tempstr[index]= '|';
+ memcpy(&tempstr[index+1], &pld.searchstr[index], 64-index);
+ }
+ else {
+ strncpy(tempstr, pld.searchstr, 64);
+ }
/* get marker name */
if (pld.marker)
diff --git a/source/blender/src/resources.c b/source/blender/src/resources.c
index 046d14c990d..f47f14a605c 100644
--- a/source/blender/src/resources.c
+++ b/source/blender/src/resources.c
@@ -52,6 +52,7 @@
#include "BIF_interface_icons.h"
#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
#include "blendef.h" // CLAMP
#include "datatoc.h"
@@ -784,6 +785,33 @@ char *BIF_ThemeColorsPup(int spacetype)
return cp;
}
+char *BIF_ThemeColorSetsPup (short inc_custom)
+{
+ DynStr *pupds= BLI_dynstr_new();
+ char *str;
+ char buf[48];
+ int i;
+
+ /* add title first (and the "default" entry) */
+ BLI_dynstr_append(pupds, "Bone Color Set%t|Default Colors%x0|");
+
+ /* loop through set indices, adding them */
+ for (i=1; i<21; i++) {
+ sprintf(buf, "%d - Theme Color Set%%x%d|", i, i);
+ BLI_dynstr_append(pupds, buf);
+ }
+
+ /* add the 'custom' entry */
+ if (inc_custom)
+ BLI_dynstr_append(pupds, "Custom Set %x-1");
+
+ /* convert to normal MEM_malloc'd string */
+ str= BLI_dynstr_get_cstring(pupds);
+ BLI_dynstr_free(pupds);
+
+ return str;
+}
+
void BIF_SetTheme(ScrArea *sa)
{
if(sa==NULL) { // called for safety, when delete themes
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 3b8bb4c3929..92efb477095 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -56,6 +56,7 @@
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h" /* used for select_same_group */
+#include "DNA_gpencil_types.h"
#include "DNA_image_types.h"
#include "DNA_ipo_types.h"
#include "DNA_mesh_types.h"
@@ -159,6 +160,7 @@
#include "BDR_imagepaint.h"
#include "BDR_sculptmode.h"
#include "BDR_unwrapper.h"
+#include "BDR_gpencil.h"
#include "BLO_readfile.h" /* for BLO_blendhandle_close */
@@ -1193,13 +1195,17 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(event==UI_BUT_EVENT) do_butspace(val); /* temporal, view3d deserves own queue? */
- /* we consider manipulator a button, defaulting to leftmouse */
+ /* - we consider manipulator a button, defaulting to leftmouse
+ * - grease-pencil also defaults to leftmouse
+ */
if(event==LEFTMOUSE) {
/* run any view3d event handler script links */
- if (event && sa->scriptlink.totscript)
+ if (event && sa->scriptlink.totscript) {
if (BPY_do_spacehandlers(sa, event, SPACEHANDLER_VIEW3D_EVENT))
return; /* return if event was processed (swallowed) by handler(s) */
-
+ }
+
+ if(gpencil_do_paint(sa)) return;
if(BIF_do_manipulator(sa)) return;
}
@@ -1207,7 +1213,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if (U.flag & USER_LMOUSESELECT) {
/* only swap mouse button for selection, in modes where it is relevant.
* painting/sculpting stays on LEFTMOUSE */
- if ( !((G.f & G_SCULPTMODE) || (G.f & G_WEIGHTPAINT) ||
+ if ( !((G.f & G_SCULPTMODE) || (G.f & G_WEIGHTPAINT) || (G.f & G_GREASEPENCIL) ||
(G.f & G_VERTEXPAINT) || (G.f & G_TEXTUREPAINT) || (G.f & G_PARTICLEEDIT)) ||
(G.obedit) )
{
@@ -1945,7 +1951,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
adduplicate(0, 0);
}
else if(G.qual==LR_CTRLKEY) {
- imagestodisplist();
+ imagestodisplist(); // removed
}
else if((G.qual==0)){
pupval= pupmenu("Draw mode%t|BoundBox %x1|Wire %x2|OpenGL Solid %x3|Shaded Solid %x4|Textured Solid %x5");
@@ -4816,6 +4822,11 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(val) {
if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
+ /* grease-pencil defaults to leftmouse */
+ if(event==LEFTMOUSE) {
+ if(gpencil_do_paint(sa)) return;
+ }
+
/* swap mouse buttons based on user preference */
if (U.flag & USER_LMOUSESELECT) {
if (event == LEFTMOUSE) {
@@ -4829,11 +4840,11 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
switch(event) {
case LEFTMOUSE:
- if(sseq->mainb || view2dmove(event)==0) {
+ if(sseq->mainb==0 && view2dmove(event)==0) {
first= 1;
set_special_seq_update(1);
-
+
do {
getmouseco_areawin(mval);
areamouseco_to_ipoco(v2d, mval, &dx, &dy);
@@ -4844,9 +4855,9 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if( cfra!=CFRA || first ) {
first= 0;
-
+
CFRA= cfra;
- force_draw(0);
+ force_draw_all(0);
update_for_newframe(); /* for audio scrubbing */
}
else PIL_sleep_ms(30);
@@ -6241,6 +6252,7 @@ void freespacelist(ScrArea *sa)
if(vd->bgpic->ima) vd->bgpic->ima->id.us--;
MEM_freeN(vd->bgpic);
}
+ if(vd->gpd) free_gpencil_data(vd->gpd);
if(vd->localvd) MEM_freeN(vd->localvd);
if(vd->clipbb) MEM_freeN(vd->clipbb);
if(vd->depths) {
@@ -6284,7 +6296,12 @@ void freespacelist(ScrArea *sa)
curvemapping_free(sima->cumap);
}
else if(sl->spacetype==SPACE_NODE) {
-/* SpaceNode *snode= (SpaceNode *)sl; */
+ SpaceNode *snode= (SpaceNode *)sl;
+ if(snode->gpd) free_gpencil_data(snode->gpd);
+ }
+ else if(sl->spacetype==SPACE_SEQ) {
+ SpaceSeq *sseq= (SpaceSeq *)sl;
+ if(sseq->gpd) free_gpencil_data(sseq->gpd);
}
}
@@ -6314,6 +6331,7 @@ void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
BIF_view3d_previewrender_free(v3d);
v3d->depths= NULL;
v3d->retopo_view_data= NULL;
+ v3d->gpd= gpencil_data_duplicate(v3d->gpd);
}
else if(sl->spacetype==SPACE_OOPS) {
SpaceOops *so= (SpaceOops *)sl;
@@ -6333,11 +6351,16 @@ void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
else if(sl->spacetype==SPACE_NODE) {
SpaceNode *snode= (SpaceNode *)sl;
snode->nodetree= NULL;
+ snode->gpd= gpencil_data_duplicate(snode->gpd);
}
else if(sl->spacetype==SPACE_SCRIPT) {
SpaceScript *sc = ( SpaceScript * ) sl;
sc->but_refs = NULL;
}
+ else if(sl->spacetype==SPACE_SEQ) {
+ SpaceSeq *sseq= (SpaceSeq *)sl;
+ sseq->gpd= gpencil_data_duplicate(sseq->gpd);
+ }
sl= sl->next;
}
diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c
index 10e49cdd218..706b079432c 100644
--- a/source/blender/src/transform_conversions.c
+++ b/source/blender/src/transform_conversions.c
@@ -70,6 +70,7 @@
#include "DNA_vfont_types.h"
#include "DNA_constraint_types.h"
#include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -125,6 +126,7 @@
#include "BDR_drawaction.h" // list of keyframes in action
#include "BDR_editobject.h" // reset_slowparents()
+#include "BDR_gpencil.h"
#include "BDR_unwrapper.h"
#include "BLI_arithb.h"
@@ -2474,6 +2476,96 @@ void flushTransIpoData(TransInfo *t)
/* ********************* ACTION/NLA EDITOR ****************** */
+/* Called by special_aftertrans_update to make sure selected gp-frames replace
+ * any other gp-frames which may reside on that frame (that are not selected).
+ * It also makes sure gp-frames are still stored in chronological order after
+ * transform.
+ */
+static void posttrans_gpd_clean (bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+
+ for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
+ ListBase sel_buffer = {NULL, NULL};
+ bGPDframe *gpf, *gpfn;
+ bGPDframe *gfs, *gfsn;
+
+ /* loop 1: loop through and isolate selected gp-frames to buffer
+ * (these need to be sorted as they are isolated)
+ */
+ for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
+ gpfn= gpf->next;
+
+ if (gpf->flag & GP_FRAME_SELECT) {
+ BLI_remlink(&gpl->frames, gpf);
+
+ /* find place to add them in buffer
+ * - go backwards as most frames will still be in order,
+ * so doing it this way will be faster
+ */
+ for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) {
+ /* if current (gpf) occurs after this one in buffer, add! */
+ if (gfs->framenum < gpf->framenum) {
+ BLI_insertlinkafter(&sel_buffer, gfs, gpf);
+ break;
+ }
+ }
+ if (gfs == NULL)
+ BLI_addhead(&sel_buffer, gpf);
+ }
+ }
+
+ /* error checking: it is unlikely, but may be possible to have none selected */
+ if (sel_buffer.first == NULL)
+ continue;
+
+ /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */
+ if (gpl->frames.first == NULL) {
+ gpl->frames.first= sel_buffer.first;
+ gpl->frames.last= sel_buffer.last;
+
+ continue;
+ }
+
+ /* loop 2: remove duplicates of frames in buffers */
+ //gfs= sel_buffer.first;
+ //gfsn= gfs->next;
+
+ for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) {
+ gpfn= gpf->next;
+
+ /* loop through sel_buffer, emptying stuff from front of buffer if ok */
+ for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) {
+ gfsn= gfs->next;
+
+ /* if this buffer frame needs to go before current, add it! */
+ if (gfs->framenum < gpf->framenum) {
+ /* transfer buffer frame to frames list (before current) */
+ BLI_remlink(&sel_buffer, gfs);
+ BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
+ }
+ /* if this buffer frame is on same frame, replace current with it and stop */
+ else if (gfs->framenum == gpf->framenum) {
+ /* transfer buffer frame to frames list (before current) */
+ BLI_remlink(&sel_buffer, gfs);
+ BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
+
+ /* get rid of current frame */
+ gpencil_layer_delframe(gpl, gpf);
+ }
+ }
+ }
+
+ /* if anything is still in buffer, append to end */
+ for (gfs= sel_buffer.first; gfs; gfs= gfsn) {
+ gfsn= gfs->next;
+
+ BLI_remlink(&sel_buffer, gfs);
+ BLI_addtail(&gpl->frames, gfs);
+ }
+ }
+}
+
/* Called by special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
*/
@@ -2698,6 +2790,26 @@ static int count_ipo_keys(Ipo *ipo, char side, float cfra)
return count;
}
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+{
+ bGPDframe *gpf;
+ int count = 0;
+
+ if (gpl == NULL)
+ return count;
+
+ /* only include points that occur on the right side of cfra */
+ for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(side, gpf->framenum, cfra))
+ count++;
+ }
+ }
+
+ return count;
+}
+
/* This function assigns the information to transdata */
static void TimeToTransData(TransData *td, float *time, Object *ob)
{
@@ -2751,9 +2863,68 @@ static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side,
return td;
}
+/* helper struct for gp-frame transforms (only used here) */
+typedef struct tGPFtransdata {
+ float val; /* where transdata writes transform */
+ int *sdata; /* pointer to gpf->framenum */
+} tGPFtransdata;
+
+/* This function helps flush transdata written to tempdata into the gp-frames */
+void flushTransGPactionData (TransInfo *t)
+{
+ tGPFtransdata *tfd;
+ int i;
+
+ /* find the first one to start from */
+ if (t->mode == TFM_TIME_SLIDE)
+ tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
+ else
+ tfd= (tGPFtransdata *)(t->customData);
+
+ /* flush data! */
+ for (i = 0; i < t->total; i++, tfd++) {
+ *(tfd->sdata)= (int)floor(tfd->val + 0.5);
+ }
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static int GPLayerToTransData (TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, short side, float cfra)
+{
+ bGPDframe *gpf;
+ int count= 0;
+
+ /* check for select frames on right side of current frame */
+ for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(side, gpf->framenum, cfra)) {
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val= &tfd->val;
+ td->ival= gpf->framenum;
+
+ tfd->val= gpf->framenum;
+ tfd->sdata= &gpf->framenum;
+
+ /* advance td now */
+ td++;
+ tfd++;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
static void createTransActionData(TransInfo *t)
{
TransData *td = NULL;
+ tGPFtransdata *tfd = NULL;
Object *ob= NULL;
ListBase act_data = {NULL, NULL};
@@ -2771,7 +2942,10 @@ static void createTransActionData(TransInfo *t)
if (data == NULL) return;
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* is the action scaled? if so, the it should belong to the active object */
@@ -2800,8 +2974,12 @@ static void createTransActionData(TransInfo *t)
cfra = CFRA;
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
- for (ale= act_data.first; ale; ale= ale->next)
- count += count_ipo_keys(ale->key_data, side, cfra);
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (ale->type == ACTTYPE_GPLAYER)
+ count += count_gplayer_frames(ale->data, side, cfra);
+ else
+ count += count_ipo_keys(ale->key_data, side, cfra);
+ }
/* stop if trying to build list if nothing selected */
if (count == 0) {
@@ -2812,16 +2990,38 @@ static void createTransActionData(TransInfo *t)
/* allocate memory for data */
t->total= count;
+
t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
- if (t->mode == TFM_TIME_SLIDE)
+ td= t->data;
+
+ if (datatype == ACTCONT_GPENCIL) {
+ if (t->mode == TFM_TIME_SLIDE) {
+ t->customData= MEM_callocN((sizeof(float)*2)+(sizeof(tGPFtransdata)*count), "TimeSlide + tGPFtransdata");
+ tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
+ }
+ else {
+ t->customData= MEM_callocN(sizeof(tGPFtransdata)*count, "tGPFtransdata");
+ tfd= (tGPFtransdata *)(t->customData);
+ }
+ }
+ else if (t->mode == TFM_TIME_SLIDE)
t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
- td= t->data;
/* loop 2: build transdata array */
for (ale= act_data.first; ale; ale= ale->next) {
- Ipo *ipo= (Ipo *)ale->key_data;
-
- td= IpoToTransData(td, ipo, ob, side, cfra);
+ if (ale->type == ACTTYPE_GPLAYER) {
+ bGPDlayer *gpl= (bGPDlayer *)ale->data;
+ int i;
+
+ i = GPLayerToTransData(td, tfd, gpl, side, cfra);
+ td += i;
+ tfd += i;
+ }
+ else {
+ Ipo *ipo= (Ipo *)ale->key_data;
+
+ td= IpoToTransData(td, ipo, ob, side, cfra);
+ }
}
/* check if we're supposed to be setting minx/maxx for TimeSlide */
@@ -3623,7 +3823,7 @@ void special_aftertrans_update(TransInfo *t)
}
}
}
- else if (t->spacetype == SPACE_ACTION) {
+ if (t->spacetype == SPACE_ACTION) {
void *data;
short datatype;
@@ -3673,6 +3873,13 @@ void special_aftertrans_update(TransInfo *t)
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
}
+ else if (datatype == ACTCONT_GPENCIL) {
+ /* remove duplicate frames and also make sure points are in order! */
+ if ((cancelled == 0) || (duplicate))
+ {
+ posttrans_gpd_clean(data);
+ }
+ }
G.saction->flag &= ~SACTION_MOVING;
}
diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c
index 6cb7a34d1bc..c332fd723eb 100644
--- a/source/blender/src/transform_generics.c
+++ b/source/blender/src/transform_generics.c
@@ -278,6 +278,11 @@ void recalcData(TransInfo *t)
data = get_action_context(&context);
if (data == NULL) return;
+ /* always flush data if gpencil context */
+ if (context == ACTCONT_GPENCIL) {
+ flushTransGPactionData(t);
+ }
+
if (G.saction->lock) {
if (context == ACTCONT_ACTION) {
if(ob) {
@@ -753,6 +758,10 @@ void postTrans (TransInfo *t)
if (G.sima->flag & SI_LIVE_UNWRAP)
unwrap_lscm_live_end(t->state == TRANS_CANCEL);
}
+ else if(t->spacetype==SPACE_ACTION) {
+ if (t->customData)
+ MEM_freeN(t->customData);
+ }
}
void applyTransObjects(TransInfo *t)
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index 4aea0df74b9..92e49ab29fa 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -883,7 +883,7 @@ void BIF_write_file(char *target)
if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE);
for (li= G.main->library.first; li; li= li->id.next) {
- if (BLI_streq(li->name, target)) {
+ if (li->parent==NULL && BLI_streq(li->name, target)) {
error("Cannot overwrite used library");
return;
}