diff options
author | Maxime Curioni <maxime.curioni@gmail.com> | 2008-07-23 10:02:18 +0400 |
---|---|---|
committer | Maxime Curioni <maxime.curioni@gmail.com> | 2008-07-23 10:02:18 +0400 |
commit | 0c494442d34d05ea8e0d94daefcca5902a2d6149 (patch) | |
tree | 8c979ad3a92731656070387594123e1ef4d7082a /source/blender | |
parent | 0c3f7c2b7e0c9d8ad5945029170fc8ed1f0c1eda (diff) | |
parent | 1ffdc6679171c40ac1b2e5852ceaaa1495fbcd17 (diff) |
soc-2008-mxcurioni: merged changes to revision 15705
Diffstat (limited to 'source/blender')
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; } |