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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Bishop <nicholasbishop@gmail.com>2008-07-27 23:53:57 +0400
committerNicholas Bishop <nicholasbishop@gmail.com>2008-07-27 23:53:57 +0400
commitec66e5e75aa48870823775a38479c647d38b9bc8 (patch)
tree3c44a2c5d46a9dda95be181fbadd0686ebea866a /source/blender/src
parent5a3572beecf86bdbdc8fe1589567f5d4d66b095b (diff)
parentf4def51cd3c225cf3bbe7895f729a29a5d4067e5 (diff)
Merged with r15805
Diffstat (limited to 'source/blender/src')
-rw-r--r--source/blender/src/buttons_editing.c13
-rw-r--r--source/blender/src/buttons_logic.c14
-rw-r--r--source/blender/src/buttons_object.c4
-rw-r--r--source/blender/src/drawaction.c227
-rw-r--r--source/blender/src/drawgpencil.c656
-rw-r--r--source/blender/src/drawnode.c77
-rw-r--r--source/blender/src/drawobject.c5
-rw-r--r--source/blender/src/drawseq.c97
-rw-r--r--source/blender/src/drawview.c122
-rw-r--r--source/blender/src/editaction.c453
-rw-r--r--source/blender/src/editaction_gpencil.c548
-rw-r--r--source/blender/src/editarmature.c26
-rw-r--r--source/blender/src/editnode.c51
-rw-r--r--source/blender/src/editobject.c6
-rw-r--r--source/blender/src/editseq.c34
-rw-r--r--source/blender/src/gpencil.c1232
-rw-r--r--source/blender/src/header_action.c364
-rw-r--r--source/blender/src/header_node.c10
-rw-r--r--source/blender/src/header_seq.c13
-rw-r--r--source/blender/src/header_view3d.c4
-rw-r--r--source/blender/src/interface.c7
-rw-r--r--source/blender/src/interface_draw.c2
-rw-r--r--source/blender/src/outliner.c72
-rw-r--r--source/blender/src/poseobject.c156
-rw-r--r--source/blender/src/sequence.c4
-rw-r--r--source/blender/src/space.c51
-rw-r--r--source/blender/src/transform_conversions.c227
-rw-r--r--source/blender/src/transform_generics.c9
-rw-r--r--source/blender/src/transform_manipulator.c10
-rw-r--r--source/blender/src/usiblender.c2
30 files changed, 4151 insertions, 345 deletions
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 08d1c66f2ca..52ed65a8936 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -1966,7 +1966,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_MODIFIER_RECALC, "Width: ",
lx, (cy -= 19), buttonWidth, 19, &bmd->value,
- 0.0, 0.5, 5, 2,
+ 0.0, 0.5, 5, 4,
"Bevel value/amount");
/*uiDefButI(block, NUM, B_MODIFIER_RECALC, "Recurs",
lx, (cy -= 19), buttonWidth, 19, &bmd->res,
@@ -4421,11 +4421,12 @@ static void editing_panel_armature_bones(Object *ob, bArmature *arm)
uiDefButF(block, NUM,B_ARM_RECALCDATA, "Weight:", 225, by-19,105, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight");
/* bone types */
- uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge", -10,by-38,80,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
- uiDefButBitI(block, TOG, BONE_NO_SCALE, B_ARM_RECALCDATA, "S", 70,by-38,20,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit scale from parent Bone");
- uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform", 90, by-38, 80, 18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
- uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 170,by-38,80,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
- uiDefButBitI(block, TOG, BONE_HIDDEN_A, REDRAWVIEW3D, "Hide", 250,by-38,80,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Edit Mode");
+ uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge", -10,by-38,60,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
+ uiDefButBitI(block, TOG, BONE_NO_SCALE, B_ARM_RECALCDATA, "S", 50,by-38,20,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit scale from parent Bone");
+ uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform", 70, by-38, 80, 18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
+ uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 150,by-38,60,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
+ uiDefButBitI(block, TOG, BONE_HIDDEN_A, REDRAWVIEW3D, "Hide", 210,by-38,60,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Edit Mode");
+ uiDefButBitI(block, TOG, BONE_EDITMODE_LOCKED, REDRAWVIEW3D, "Lock", 270,by-38,60,18, &curBone->flag, 0, 0, 0, 0, "Prevents this bone from being transformed in Edit Mode");
/* layers */
uiBlockBeginAlign(block);
diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c
index 441d00ffc30..498edc0dfed 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,12 +2084,12 @@ 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");
- if(coa->mode & (ACT_CONST_DIRPX|ACT_CONST_DIRMX)) fp= coa->minloc;
- else if(coa->mode & (ACT_CONST_DIRPY|ACT_CONST_DIRMY)) fp= coa->minloc+1;
+ if(coa->mode & (ACT_CONST_DIRPX|ACT_CONST_DIRNX)) fp= coa->minloc;
+ else if(coa->mode & (ACT_CONST_DIRPY|ACT_CONST_DIRNY)) fp= coa->minloc+1;
else fp= coa->minloc+2;
uiDefButF(block, NUM, 0, "", xco+80, yco-65, (width-115)/2, 19, fp+3, 0.0, 2000.0, 10, 0, "Maximum length 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, "");
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
index ebe770c89e7..2c7802c3302 100644
--- a/source/blender/src/buttons_object.c
+++ b/source/blender/src/buttons_object.c
@@ -480,7 +480,7 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short
/* Target-Space */
if (target == 1) {
- uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1",
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1",
tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in");
}
else if (target == 0) {
@@ -490,7 +490,7 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short
/* Owner-Space */
if (owner == 1) {
- uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1",
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1",
ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");
}
else if (owner == 0) {
diff --git a/source/blender/src/drawaction.c b/source/blender/src/drawaction.c
index 6fe37c1c6e5..0782ccfc7ee 100644
--- a/source/blender/src/drawaction.c
+++ b/source/blender/src/drawaction.c
@@ -58,6 +58,7 @@
#include "DNA_constraint_types.h"
#include "DNA_key_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_gpencil_types.h"
#include "BKE_action.h"
#include "BKE_depsgraph.h"
@@ -74,6 +75,7 @@
#include "BIF_editnla.h"
#include "BIF_interface.h"
#include "BIF_interface_icons.h"
+#include "BIF_drawgpencil.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BIF_resources.h"
@@ -83,9 +85,11 @@
#include "BDR_drawaction.h"
#include "BDR_editcurve.h"
+#include "BDR_gpencil.h"
#include "BSE_drawnla.h"
#include "BSE_drawipo.h"
+#include "BSE_drawview.h"
#include "BSE_editaction_types.h"
#include "BSE_editipo.h"
#include "BSE_time.h"
@@ -464,7 +468,7 @@ static void draw_channel_names(void)
bActionGroup *grp = NULL;
short indent= 0, offset= 0, sel= 0, group=0;
int expand= -1, protect = -1, special= -1, mute = -1;
- char name[32];
+ char name[64];
/* determine what needs to be drawn */
switch (ale->type) {
@@ -622,12 +626,112 @@ static void draw_channel_names(void)
sprintf(name, "Constraint");
}
break;
+ case ACTTYPE_GPDATABLOCK: /* gpencil datablock */
+ {
+ bGPdata *gpd = (bGPdata *)ale->data;
+ ScrArea *sa = (ScrArea *)ale->owner;
+
+ indent = 0;
+ group= 3;
+
+ /* only show expand if there are any channels */
+ if (gpd->layers.first) {
+ if (gpd->flag & GP_DATA_EXPAND)
+ expand = ICON_TRIA_DOWN;
+ else
+ expand = ICON_TRIA_RIGHT;
+ }
+
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ /* this shouldn't cause any overflow... */
+ sprintf(name, "3DView: %s", view3d_get_name(sa->spacedata.first));
+ special= ICON_VIEW3D;
+ }
+ break;
+ case SPACE_NODE:
+ {
+ SpaceNode *snode= sa->spacedata.first;
+ char treetype[12];
+
+ if (snode->treetype == 1)
+ sprintf(treetype, "Composite");
+ else
+ sprintf(treetype, "Material");
+ sprintf(name, "Nodes: %s", treetype);
+
+ special= ICON_NODE;
+ }
+ break;
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq= sa->spacedata.first;
+ char imgpreview[10];
+
+ switch (sseq->mainb) {
+ case 1: sprintf(imgpreview, "Image..."); break;
+ case 2: sprintf(imgpreview, "Luma..."); break;
+ case 3: sprintf(imgpreview, "Chroma..."); break;
+ case 4: sprintf(imgpreview, "Histogram"); break;
+
+ default: sprintf(imgpreview, "Sequence"); break;
+ }
+ sprintf(name, "Sequencer: %s", imgpreview);
+
+ special= ICON_SEQUENCE;
+ }
+ break;
+
+ default:
+ {
+ sprintf(name, "<Unknown GP-Data Source>");
+ special= -1;
+ }
+ break;
+ }
+ }
+ break;
+ case ACTTYPE_GPLAYER: /* gpencil layer */
+ {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+
+ indent = 0;
+ special = -1;
+ expand = -1;
+ group = 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 */
/* draw backing strip behind channel name */
- if (group == 2) {
- /* only for group-channels */
+ if (group == 3) {
+ /* only for gp-data channels */
+ if (ale->owner == curarea) // fixme... currently useless
+ BIF_ThemeColorShade(TH_GROUP_ACTIVE, 10);
+ else
+ BIF_ThemeColorShade(TH_GROUP, 20);
+ uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
+ gl_round_box(GL_POLYGON, x, yminc, (float)NAMEWIDTH, ymaxc, 8);
+
+ offset = 0;
+ }
+ else if (group == 2) {
+ /* only for action group channels */
if (ale->flag & AGRP_ACTIVE)
BIF_ThemeColorShade(TH_GROUP_ACTIVE, 10);
else
@@ -673,13 +777,19 @@ static void draw_channel_names(void)
offset += 17;
}
- /* draw special icon indicating type of ipo-blocktype?
- * only for expand widgets for Ipo and Constraint Channels
- */
- if (special > 0) {
- offset = (group) ? 29 : 24;
- BIF_icon_draw(x+offset, yminc, special);
- offset += 17;
+ /* draw special icon indicating certain data-types */
+ if (special > -1) {
+ if (group == 3) {
+ /* for gpdatablock channels */
+ BIF_icon_draw(x+offset, yminc, special);
+ offset += 17;
+ }
+ else {
+ /* for ipo/constraint channels */
+ offset = (group) ? 29 : 24;
+ BIF_icon_draw(x+offset, yminc, special);
+ offset += 17;
+ }
}
/* draw name */
@@ -695,13 +805,13 @@ static void draw_channel_names(void)
offset = 0;
/* draw protect 'lock' */
- if (protect > 0) {
+ if (protect > -1) {
offset = 16;
BIF_icon_draw(NAMEWIDTH-offset, yminc, protect);
}
/* draw mute 'eye' */
- if (mute > 0) {
+ if (mute > -1) {
offset += 16;
BIF_icon_draw(NAMEWIDTH-offset, yminc, mute);
}
@@ -827,6 +937,12 @@ static void draw_channel_strips(void)
sel = SEL_ICU(icu);
}
break;
+ case ACTTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ sel = SEL_GPL(gpl);
+ }
+ break;
}
if (datatype == ACTCONT_ACTION) {
@@ -865,6 +981,19 @@ static void draw_channel_strips(void)
glColor4ub(col2[0], col2[1], col2[2], 0x44);
glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax, channel_y+CHANNELHEIGHT/2);
}
+ else if (datatype == ACTCONT_GPENCIL) {
+ gla2DDrawTranslatePt(di, G.v2d->cur.xmin, y, &frame1_x, &channel_y);
+
+ /* frames less than one get less saturated background */
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ glRectf(0, channel_y-CHANNELHEIGHT/2, frame1_x, channel_y+CHANNELHEIGHT/2);
+
+ /* frames one and higher get a saturated background */
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x44);
+ glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax, channel_y+CHANNELHEIGHT/2);
+ }
}
/* Increment the step */
@@ -899,6 +1028,9 @@ static void draw_channel_strips(void)
case ALE_ICU:
draw_icu_channel(di, ale->key_data, y);
break;
+ case ALE_GPFRAME:
+ draw_gpl_channel(di, ale->data, y);
+ break;
}
}
@@ -1075,6 +1207,7 @@ void drawactionspace(ScrArea *sa, void *spacedata)
{
bAction *act = NULL;
Key *key = NULL;
+ bGPdata *gpd = NULL;
void *data;
short datatype;
@@ -1090,18 +1223,32 @@ 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;
+ }
}
/* get data */
data = get_action_context(&datatype);
- if (datatype == ACTCONT_ACTION)
- act = data;
- else if (datatype == ACTCONT_SHAPEKEY)
- key = data;
+ switch (datatype) {
+ case ACTCONT_ACTION:
+ act = data;
+ break;
+ case ACTCONT_SHAPEKEY:
+ key = data;
+ break;
+ case ACTCONT_GPENCIL:
+ gpd = data;
+ break;
+ }
/* Lets make sure the width of the left hand of the screen
* is set to an appropriate value based on whether sliders
@@ -1450,10 +1597,15 @@ static ActKeysInc *init_aki_data()
static ActKeysInc aki;
/* init data of static struct here */
- if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED)
+ if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED &&
+ (G.saction->mode == SACTCONT_ACTION))
+ {
aki.ob= OBACT;
+ }
else if (curarea->spacetype == SPACE_NLA)
+ {
aki.ob= NULL; // FIXME
+ }
else
aki.ob= NULL;
@@ -1528,6 +1680,16 @@ void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
BLI_freelistN(&keys);
}
+void draw_gpl_channel(gla2DDrawInfo *di, bGPDlayer *gpl, float ypos)
+{
+ ListBase keys = {0, 0};
+ ActKeysInc *aki = init_aki_data();
+
+ gpl_to_keylist(gpl, &keys, NULL, aki);
+ draw_keylist(di, &keys, NULL, ypos);
+ BLI_freelistN(&keys);
+}
+
/* --------------- Conversion: data -> keyframe list ------------------ */
void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
@@ -1674,3 +1836,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..e07dec90629
--- /dev/null
+++ b/source/blender/src/drawgpencil.c
@@ -0,0 +1,656 @@
+/**
+ * $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);
+ allqueue(REDRAWACTION, 0);
+}
+
+/* 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);
+ allqueue(REDRAWACTION, 0);
+}
+
+/* add a new layer */
+void gp_ui_addlayer_cb (void *gpd, void *dummy)
+{
+ gpencil_layer_addnew(gpd);
+ allqueue(REDRAWACTION, 0);
+}
+
+/* delete active layer */
+void gp_ui_dellayer_cb (void *gpd, void *dummy)
+{
+ gpencil_layer_delactive(gpd);
+ allqueue(REDRAWACTION, 0);
+}
+
+/* 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);
+
+ allqueue(REDRAWACTION, 0);
+}
+
+/* ------- 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 active= (gpl->flag & GP_LAYER_ACTIVE);
+ 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 */
+ if (active) uiBlockSetCol(block, TH_BUT_ACTION);
+ rb_col= (active)?-20:20;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15 , rb_col-20, "");
+ if (active) uiBlockSetCol(block, TH_AUTO);
+
+ /* 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, only draw header */
+ if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) {
+ char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */
+
+ height= 26;
+
+ /* 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 */
+ if (gpl->flag & GP_LAYER_HIDE)
+ sprintf(name, "%s (Hidden)", gpl->info);
+ else
+ sprintf(name, "%s (Locked)", gpl->info);
+ uiDefBut(block, LABEL, 1, name, *xco+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "Short description of what this layer is for (optional)");
+
+ /* delete button (only if hidden but not locked!) */
+ if ((gpl->flag & GP_LAYER_HIDE) & !(gpl->flag & GP_LAYER_LOCKED)) {
+ 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);
+ }
+ else {
+ height= 97;
+
+ /* 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+36, *yco, 240, 19, 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 */
+ if (active) uiBlockSetCol(block, TH_BUT_ACTION);
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+ if (active) uiBlockSetCol(block, TH_AUTO);
+
+ /* 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)");
+
+ /* debugging options */
+ if (G.f & G_DEBUG) {
+ uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco, *yco-95, 150, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
+ }
+
+ /* 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, "Max number of frames on either side of active frame to show (0 = just 'first' available sketch on either side)");
+ uiBlockEndAlign(block);
+
+ /* options */
+ uiBlockBeginAlign(block);
+ 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 (Hotkey = Alt-XKEY/DEL)");
+ 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 (Hotkey = Alt-XKEY/DEL)");
+ uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl);
+ uiBlockEndAlign(block);
+ }
+ }
+
+ /* 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)
+ * which is basically the top left-hand corner
+ * 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= 170;
+
+ /* draw gpd settings first */
+ {
+ /* add new layer buttons */
+ but= uiDefBut(block, BUT, B_REDR, "Add New Layer", 10,205,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 + painting lock */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret LMB-click as new strokes (same as holding Shift-Key per stroke)");
+
+ uiBlockSetCol(block, TH_BUT_SETTING);
+ uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED, 300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)");
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockEndAlign(block);
+
+ /* 'view align' button (naming depends on context) */
+ if (sa->spacetype == SPACE_VIEW3D)
+ uiDefButBitI(block, TOG, GP_DATA_VIEWALIGN, B_REDR, "Sketch 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");
+ }
+
+ /* 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 a set of strokes */
+static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, short debug,
+ short lthick, float color[4])
+{
+ bGPDstroke *gps;
+
+ /* set color first (may need to reset it again later too) */
+ glColor4f(color[0], color[1], color[2], color[3]);
+
+ for (gps= gpf->strokes.first; gps; gps= gps->next) {
+ /* just draw the stroke once */
+ gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+ }
+}
+
+/* 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;
+
+ short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
+ short lthick= gpl->thickness;
+ float color[4], tcolor[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
+ QUATCOPY(tcolor, gpl->color); // additional copy of color (for ghosting)
+ 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 */
+ tcolor[3] = color[3] - (i * 0.7);
+ gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
+ }
+ 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 */
+ tcolor[3] = color[3] - (i * 0.7);
+ gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
+ }
+ 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) */
+ if (gpf->prev) {
+ tcolor[3] = (color[3] / 7);
+ gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
+ }
+
+ if (gpf->next) {
+ tcolor[3] = (color[3] / 4);
+ gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
+ }
+
+ /* restore alpha */
+ glColor4f(color[0], color[1], color[2], color[3]);
+ }
+ }
+
+ /* draw the strokes already in active frame */
+ tcolor[3]= color[3];
+ gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor);
+
+ /* 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..853df3bedfc 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 (draw using Shift-LMB)");
+
+ /* 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..cc431c73a2e 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 (draw using Shift-LMB)");
+
+ /* 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..2030eb658de 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"
@@ -1499,44 +1502,52 @@ static void draw_view_icon(void)
glDisable(GL_BLEND);
}
-static void draw_viewport_name(ScrArea *sa)
+char *view3d_get_name(View3D *v3d)
{
char *name = NULL;
- char *printable = NULL;
- switch(G.vd->view) {
+ switch (v3d->view) {
case 1:
- if (G.vd->persp == V3D_ORTHO)
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Ortho" : "Front Ortho";
+ if (v3d->persp == V3D_ORTHO)
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Ortho" : "Front Ortho";
else
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Persp" : "Front Persp";
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Persp" : "Front Persp";
break;
case 3:
- if (G.vd->persp == V3D_ORTHO)
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Ortho" : "Right Ortho";
+ if (v3d->persp == V3D_ORTHO)
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Ortho" : "Right Ortho";
else
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Persp" : "Right Persp";
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Persp" : "Right Persp";
break;
case 7:
- if (G.vd->persp == V3D_ORTHO)
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Ortho" : "Top Ortho";
+ if (v3d->persp == V3D_ORTHO)
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Ortho" : "Top Ortho";
else
- name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Persp" : "Top Persp";
+ name = (v3d->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Persp" : "Top Persp";
break;
default:
- if (G.vd->persp==V3D_CAMOB) {
- if ((G.vd->camera) && (G.vd->camera->type == OB_CAMERA)) {
+ if (v3d->persp==V3D_CAMOB) {
+ if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
Camera *cam;
- cam = G.vd->camera->data;
+ cam = v3d->camera->data;
name = (cam->type != CAM_ORTHO) ? "Camera Persp" : "Camera Ortho";
} else {
name = "Object as Camera";
}
} else {
- name = (G.vd->persp == V3D_ORTHO) ? "User Ortho" : "User Persp";
+ name = (v3d->persp == V3D_ORTHO) ? "User Ortho" : "User Persp";
}
+ break;
}
+ return name;
+}
+
+static void draw_viewport_name(ScrArea *sa)
+{
+ char *name = view3d_get_name(sa->spacedata.first);
+ char *printable = NULL;
+
if (G.vd->localview) {
printable = malloc(strlen(name) + strlen(" (Local)_")); /* '_' gives space for '\0' */
strcpy(printable, name);
@@ -1984,6 +1995,8 @@ static void v3d_editarmature_buts(uiBlock *block, Object *ob, float lim)
tfp->ob_eul[0]= 180.0*ebone->roll/M_PI;
uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, "");
+ uiDefButBitI(block, TOG, BONE_EDITMODE_LOCKED, REDRAWVIEW3D, "Lock", 160, 100, 140, 19, &(ebone->flag), 0, 0, 0, 0, "Prevents bone from being transformed in edit mode");
+
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailRadius:", 10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, "");
if (ebone->parent && ebone->flag & BONE_CONNECTED )
@@ -2498,7 +2511,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 +2559,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 +2633,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 (draw using Shift-LMB)");
+
+ /* 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 +2690,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 +2705,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 +3226,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 +3272,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 +3377,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 +3442,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 4cc0e52ce3f..c454715b1df 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,49 @@ static void actdata_filter_shapekey (ListBase *act_data, Key *key, int filter_mo
}
}
+
+static void actdata_filter_gpencil (ListBase *act_data, bScreen *sc, int filter_mode)
+{
+ bActListElem *ale;
+ ScrArea *sa;
+ bGPdata *gpd;
+ bGPDlayer *gpl;
+
+ /* check if filtering types are appropriate */
+ if ( !(filter_mode & (ACTFILTER_IPOKEYS|ACTFILTER_ONLYICU|ACTFILTER_ACTGROUPED)) )
+ {
+ /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ /* try to get gp data */
+ gpd= gpencil_data_getactive(sa);
+ if (gpd == NULL) continue;
+
+ /* add gpd as channel too (if for drawing, and it has layers) */
+ if ((filter_mode & ACTFILTER_FORDRAWING) && (gpd->layers.first)) {
+ /* add to list */
+ ale= make_new_actlistelem(gpd, ACTTYPE_GPDATABLOCK, sa, ACTTYPE_SPECIALDATA);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+
+ /* only add layers if they will be visible (if drawing channels) */
+ if ( !(filter_mode & ACTFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
+ /* 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, gpd, ACTTYPE_GPDATABLOCK);
+ 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 +580,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 */
@@ -599,11 +657,8 @@ int get_nearest_key_num (Key *key, short *mval, float *x)
return (num + 1);
}
-/* this function is used to get a pointer to an action or shapekey
- * datablock, thus simplying that process.
- */
-/* this function is intended for use */
-void *get_nearest_act_channel (short mval[], short *ret_type)
+/* this function finds the channel that mouse is floating over */
+void *get_nearest_act_channel (short mval[], short *ret_type, void **owner)
{
ListBase act_data = {NULL, NULL};
bActListElem *ale;
@@ -614,6 +669,9 @@ void *get_nearest_act_channel (short mval[], short *ret_type)
int clickmin, clickmax;
float x,y;
+ /* init 'owner' return val */
+ *owner= NULL;
+
/* determine what type of data we are operating on */
data = get_action_context(&datatype);
if (data == NULL) {
@@ -641,6 +699,7 @@ void *get_nearest_act_channel (short mval[], short *ret_type)
/* found match */
*ret_type= ale->type;
data= ale->data;
+ *owner= ale->owner;
BLI_freelistN(&act_data);
@@ -743,6 +802,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 +829,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 +862,40 @@ 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;
+ return G.curscreen; // FIXME: add that dopesheet type thing here!
+
+ default: /* includes SACTCONT_DOPESHEET for now */
+ *datatype= ACTCONT_NONE;
+ return NULL;
+ }
}
else {
- *datatype= ACTCONT_NONE;
- return NULL;
+ /* resort to guessing based on what is available */
+ if (act) {
+ *datatype= ACTCONT_ACTION;
+ return act;
+ }
+ else if (key) {
+ *datatype= ACTCONT_SHAPEKEY;
+ return key;
+ }
+ else {
+ *datatype= ACTCONT_NONE;
+ return NULL;
+ }
}
}
@@ -1307,12 +1397,18 @@ void duplicate_action_keys (void)
if (data == NULL) return;
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* loop through filtered data and duplicate selected keys */
for (ale= act_data.first; ale; ale= ale->next) {
- duplicate_ipo_keys((Ipo *)ale->key_data);
+ if (ale->type == ACTTYPE_GPLAYER)
+ duplicate_gplayer_frames(ale->data);
+ else
+ duplicate_ipo_keys((Ipo *)ale->key_data);
}
/* free filtered list */
@@ -1398,7 +1494,10 @@ void snap_action_keys(short mode)
}
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* snap to frame */
@@ -1408,6 +1507,8 @@ void snap_action_keys(short mode)
snap_ipo_keys(ale->key_data, mode);
actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
}
+ else if (ale->type == ACTTYPE_GPLAYER)
+ snap_gplayer_frames(ale->data, mode);
else
snap_ipo_keys(ale->key_data, mode);
}
@@ -1421,6 +1522,7 @@ void snap_action_keys(short mode)
allqueue(REDRAWACTION, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWVIEW3D, 0);
}
/* this function is responsible for snapping keyframes to frame-times */
@@ -1456,7 +1558,10 @@ void mirror_action_keys(short mode)
}
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* mirror */
@@ -1466,6 +1571,8 @@ void mirror_action_keys(short mode)
mirror_ipo_keys(ale->key_data, mode);
actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
}
+ else if (ale->type == ACTTYPE_GPLAYER)
+ mirror_gplayer_frames(ale->data, mode);
else
mirror_ipo_keys(ale->key_data, mode);
}
@@ -1550,6 +1657,10 @@ void insertkey_action(void)
}
}
}
+ else {
+ /* this tool is not supported in this mode */
+ return;
+ }
BIF_undo_push("Insert Key");
allspace(REMAKEIPO, 0);
@@ -1573,12 +1684,18 @@ void delete_action_keys (void)
if (data == NULL) return;
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* loop through filtered data and delete selected keys */
for (ale= act_data.first; ale; ale= ale->next) {
- delete_ipo_keys((Ipo *)ale->key_data);
+ if (ale->type == ACTTYPE_GPLAYER)
+ delete_gplayer_frames((bGPDlayer *)ale->data);
+ else
+ delete_ipo_keys((Ipo *)ale->key_data);
}
/* free filtered list */
@@ -1699,6 +1816,7 @@ void clean_action (void)
0.0000001f, 1.0, 0.001, 0.1,
"Clean Threshold");
if (!ok) return;
+ if (datatype == ACTCONT_GPENCIL) return;
/* filter data */
filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_SEL | ACTFILTER_ONLYICU);
@@ -1737,6 +1855,7 @@ void sample_action_keys (void)
/* sanity checks */
data= get_action_context(&datatype);
if (data == NULL) return;
+ if (datatype == ACTCONT_GPENCIL) return;
/* filter data */
filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
@@ -2096,6 +2215,7 @@ void action_set_ipo_flags (short mode, short event)
/* determine what type of data we are operating on */
data = get_action_context(&datatype);
if (data == NULL) return;
+ if (datatype == ACTCONT_GPENCIL) return;
/* determine which set of processing we are doing */
switch (mode) {
@@ -2194,6 +2314,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);
@@ -2224,7 +2345,7 @@ static void numbuts_action ()
void *data;
short datatype;
- void *act_channel;
+ void *act_channel, *channel_owner;
short chantype;
bActionGroup *agrp= NULL;
@@ -2232,11 +2353,13 @@ static void numbuts_action ()
bConstraintChannel *conchan= NULL;
IpoCurve *icu= NULL;
KeyBlock *kb= NULL;
+ bGPdata *gpd= NULL;
+ bGPDlayer *gpl= NULL;
short mval[2];
int but=0;
- char str[64];
+ char str[128];
short expand, protect, mute;
float slidermin, slidermax;
@@ -2249,7 +2372,7 @@ static void numbuts_action ()
getmouseco_areawin(mval);
if (mval[0] > NAMEWIDTH)
return;
- act_channel= get_nearest_act_channel(mval, &chantype);
+ act_channel= get_nearest_act_channel(mval, &chantype, &channel_owner);
/* create items for clever-numbut */
if (chantype == ACTTYPE_ACHAN) {
@@ -2345,6 +2468,19 @@ 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 */
+ gpd= (bGPdata *)channel_owner;
+ gpl= (bGPDlayer *)act_channel;
+
+ strcpy(str, gpl->info);
+ protect= (gpl->flag & GP_LAYER_LOCKED);
+ mute = (gpl->flag & GP_LAYER_HIDE);
+
+ add_numbut(but++, TEX, "GP-Layer: ", 0, 128, str, "Name of Grease Pencil Layer");
+ add_numbut(but++, TOG|SHO, "Hide", 0, 24, &mute, "Grease Pencil Layer is Visible");
+ add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Grease Pencil Layer is Protected");
+ }
else {
/* nothing under-cursor */
return;
@@ -2393,6 +2529,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(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info), 128);
+
+ if (mute) gpl->flag |= GP_LAYER_HIDE;
+ else gpl->flag &= ~GP_LAYER_HIDE;;
+
+ if (protect) gpl->flag |= GP_LAYER_LOCKED;
+ else gpl->flag &= ~GP_LAYER_LOCKED;
+ }
allqueue(REDRAWACTION, 0);
allspace(REMAKEIPO, 0);
@@ -2524,6 +2670,31 @@ void setflag_action_channels (short mode)
}
}
break;
+ case ACTTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl= (bGPDlayer *)ale->data;
+
+ /* 'protect' and 'mute' */
+ if (val == 2) {
+ /* mute */
+ if (mode == 2)
+ gpl->flag &= ~GP_LAYER_HIDE;
+ else if (mode == 1)
+ gpl->flag |= GP_LAYER_HIDE;
+ else
+ gpl->flag ^= GP_LAYER_HIDE;
+ }
+ else if (val == 1) {
+ /* protected */
+ if (mode == 2)
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ else if (mode == 1)
+ gpl->flag |= GP_LAYER_LOCKED;
+ else
+ gpl->flag ^= GP_LAYER_LOCKED;
+ }
+ }
+ break;
}
}
BLI_freelistN(&act_data);
@@ -2564,7 +2735,7 @@ static void select_action_group (bAction *act, bActionGroup *agrp, int selectmod
set_active_actiongroup(act, agrp, select);
}
-static void hilight_channel(bAction *act, bActionChannel *achan, short select)
+static void hilight_channel (bAction *act, bActionChannel *achan, short select)
{
bActionChannel *curchan;
@@ -2637,7 +2808,7 @@ void select_actionchannel_by_name (bAction *act, char *name, int select)
/* exported for outliner (ton) */
/* apparently within active object context */
-int select_channel(bAction *act, bActionChannel *achan, int selectmode)
+int select_channel (bAction *act, bActionChannel *achan, int selectmode)
{
/* Select the channel based on the selection mode */
int flag;
@@ -2661,9 +2832,9 @@ int select_channel(bAction *act, bActionChannel *achan, int selectmode)
return flag;
}
-static int select_constraint_channel(bAction *act,
- bConstraintChannel *conchan,
- int selectmode)
+static int select_constraint_channel (bAction *act,
+ bConstraintChannel *conchan,
+ int selectmode)
{
/* Select the constraint channel based on the selection mode */
int flag;
@@ -2684,7 +2855,7 @@ static int select_constraint_channel(bAction *act,
return flag;
}
-int select_icu_channel(bAction *act, IpoCurve *icu, int selectmode)
+int select_icu_channel (bAction *act, IpoCurve *icu, int selectmode)
{
/* Select the channel based on the selection mode */
int flag;
@@ -2704,6 +2875,30 @@ 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;
+ if (flag)
+ gpencil_layer_setactive(gpd, gpl);
+
+ return flag;
+}
+
/* select only the active action-group's action channels */
void select_action_group_channels (bAction *act, bActionGroup *agrp)
@@ -2848,6 +3043,8 @@ void deselect_action_channels (short mode)
/* based on type */
if (datatype == ACTCONT_ACTION)
deselect_actionchannels(data, mode);
+ else if (datatype == ACTCONT_GPENCIL)
+ deselect_gpencil_layers(data, mode);
// should shapekey channels be allowed to do this?
}
@@ -2863,24 +3060,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 */
@@ -2908,11 +3121,11 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
switch (mode) {
case 0: /* all in channel*/
{
- void *act_channel;
+ void *act_channel, *channel_owner;
short chantype;
/* get channel, and act according to type */
- act_channel= get_nearest_act_channel(mval, &chantype);
+ act_channel= get_nearest_act_channel(mval, &chantype, &channel_owner);
switch (chantype) {
case ACTTYPE_GROUP:
{
@@ -2946,6 +3159,12 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
select_icu_bezier_keys(icu, select_mode);
}
break;
+ case ACTTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl= (bGPDlayer *)act_channel;
+ select_gpencil_frames(gpl, select_mode);
+ }
+ break;
}
}
break;
@@ -2971,12 +3190,16 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
rectf.xmax = rectf.xmax + 0.5;
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* Now set the flags */
- for (ale= act_data.first; ale; ale= ale->next)
+ for (ale= act_data.first; ale; ale= ale->next) {
borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, select_mode);
+ }
/* Cleanup */
BLI_freelistN(&act_data);
@@ -3058,19 +3281,23 @@ void selectkeys_leftright (short leftright, short select_mode)
}
/* filter data */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* select keys on the side where most data occurs */
for (ale= act_data.first; ale; ale= ale->next) {
- if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
}
- else {
+ else if (ale->type == ACTTYPE_GPLAYER)
+ borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
+ else
borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
- }
}
/* Cleanup */
@@ -3108,7 +3335,10 @@ void nextprev_action_keyframe (short dir)
return;
/* get list of keyframes that can be used (in global-time) */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
for (ale= act_data.first; ale; ale= ale->next) {
@@ -3117,6 +3347,8 @@ void nextprev_action_keyframe (short dir)
make_cfra_list(ale->key_data, &elems);
actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
}
+ else if (ale->type == ACTTYPE_GPLAYER)
+ gplayer_make_cfra_list(ale->key_data, &elems, 0);
else
make_cfra_list(ale->key_data, &elems);
}
@@ -3199,11 +3431,20 @@ void column_select_action_keys (int mode)
/* build list of columns */
switch (mode) {
case 1: /* list of selected keys */
- filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
- actdata_filter(&act_data, filter, data, datatype);
-
- for (ale= act_data.first; ale; ale= ale->next)
- make_sel_cfra_list(ale->key_data, &elems);
+ if (datatype == ACTCONT_GPENCIL) {
+ filter= (ACTFILTER_VISIBLE);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next)
+ gplayer_make_cfra_list(ale->data, &elems, 1);
+ }
+ else {
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next)
+ make_sel_cfra_list(ale->key_data, &elems);
+ }
BLI_freelistN(&act_data);
break;
@@ -3231,19 +3472,34 @@ void column_select_action_keys (int mode)
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
+ if (datatype == ACTCONT_GPENCIL)
+ filter= (ACTFILTER_VISIBLE);
+ else
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
actdata_filter(&act_data, filter, data, datatype);
for (ale= act_data.first; ale; ale= ale->next) {
for (ce= elems.first; ce; ce= ce->next) {
- for (icu= ale->key_data; icu; icu= icu->next) {
- BezTriple *bezt;
- int verts = 0;
+ /* select elements with frame number matching cfraelem */
+ if (ale->type == ACTTYPE_GPLAYER) {
+ bGPDlayer *gpl= (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
- for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
- if (bezt) {
- if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
- bezt->f2 |= 1;
+ for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+ if ( (int)ce->cfra == gpf->framenum )
+ gpf->flag |= GP_FRAME_SELECT;
+ }
+ }
+ else {
+ for (icu= ale->key_data; icu; icu= icu->next) {
+ BezTriple *bezt;
+ int verts = 0;
+
+ for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
+ if (bezt) {
+ if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
+ bezt->f2 |= 1;
+ }
}
}
}
@@ -3272,7 +3528,7 @@ void borderselect_actionchannels (void)
/* determine what type of data we are operating on */
data = get_action_context(&datatype);
if (data == NULL) return;
- if (datatype != ACTCONT_ACTION) return;
+ if (ELEM(datatype, ACTCONT_ACTION, ACTCONT_GPENCIL)==0) return;
/* draw and handle the borderselect stuff (ui) and get the select rect */
if ( (val = get_border(&rect, 3)) ) {
@@ -3344,6 +3600,16 @@ void borderselect_actionchannels (void)
icu->flag &= ~IPO_SELECT;
}
break;
+ case ACTTYPE_GPLAYER: /* grease-pencil layer */
+ {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+
+ if (selectmode == SELECT_ADD)
+ gpl->flag |= GP_LAYER_SELECT;
+ else
+ gpl->flag &= ~GP_LAYER_SELECT;
+ }
+ break;
}
/* select action-channel 'owner' */
@@ -3460,6 +3726,9 @@ void borderselect_action (void)
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
}
}
+ else if (ale->type == ACTTYPE_GPLAYER) {
+ borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ }
break;
case ACTEDIT_BORDERSEL_CHA: /* all in channel(s) */
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -3481,6 +3750,9 @@ void borderselect_action (void)
select_ipo_bezier_keys(conchan->ipo, selectmode);
}
}
+ else if (ale->type == ACTTYPE_GPLAYER) {
+ select_gpencil_frames(ale->data, selectmode);
+ }
}
break;
default: /* any keyframe inside region defined by region */
@@ -3503,6 +3775,9 @@ void borderselect_action (void)
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
}
}
+ else if (ale->type == ACTTYPE_GPLAYER) {
+ borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ }
}
}
@@ -3533,6 +3808,8 @@ static void mouse_action (int selectmode)
bActionChannel *achan= NULL;
bConstraintChannel *conchan= NULL;
IpoCurve *icu= NULL;
+ bGPdata *gpd = NULL;
+ bGPDlayer *gpl = NULL;
TimeMarker *marker, *pmarker;
void *act_channel;
@@ -3543,6 +3820,7 @@ static void mouse_action (int selectmode)
data = get_action_context(&datatype);
if (data == NULL) return;
if (datatype == ACTCONT_ACTION) act= (bAction *)data;
+ if (datatype == ACTCONT_GPENCIL) gpd= (bGPdata *)data;
act_channel= get_nearest_action_key(&selx, &sel, &act_type, &achan);
marker= find_nearest_marker(SCE_MARKERS, 1);
@@ -3615,6 +3893,9 @@ static void mouse_action (int selectmode)
case ACTTYPE_GROUP:
agrp= (bActionGroup *)act_channel;
break;
+ case ACTTYPE_GPLAYER:
+ gpl= (bGPDlayer *)act_channel;
+ break;
default:
return;
}
@@ -3638,6 +3919,13 @@ static void mouse_action (int selectmode)
set_active_actiongroup(act, agrp, 1);
}
}
+ else if (datatype == ACTCONT_GPENCIL) {
+ deselect_action_channels(0);
+
+ /* Highlight gpencil layer */
+ gpl->flag |= GP_LAYER_SELECT;
+ gpencil_layer_setactive(gpd, gpl);
+ }
}
if (icu)
@@ -3654,6 +3942,8 @@ static void mouse_action (int selectmode)
select_ipo_key(conchan->ipo, selx, selectmode);
}
}
+ else if (gpl)
+ select_gpencil_frame(gpl, selx, selectmode);
std_rmouse_transform(transform_action_keys);
@@ -3670,7 +3960,7 @@ static void mouse_action (int selectmode)
static void mouse_actionchannels (short mval[])
{
bAction *act= G.saction->action;
- void *data, *act_channel;
+ void *data, *act_channel, *channel_owner;
short datatype, chantype;
/* determine what type of data we are operating on */
@@ -3678,7 +3968,7 @@ static void mouse_actionchannels (short mval[])
if (data == NULL) return;
/* get channel to work on */
- act_channel= get_nearest_act_channel(mval, &chantype);
+ act_channel= get_nearest_act_channel(mval, &chantype, &channel_owner);
/* action to take depends on what channel we've got */
switch (chantype) {
@@ -3816,6 +4106,39 @@ static void mouse_actionchannels (short mval[])
}
}
break;
+ case ACTTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd= (bGPdata *)act_channel;
+
+ /* toggle expand */
+ gpd->flag ^= GP_DATA_EXPAND;
+ }
+ break;
+ case ACTTYPE_GPLAYER:
+ {
+ bGPdata *gpd= (bGPdata *)channel_owner;
+ 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 */
+ if (G.qual & LR_SHIFTKEY) {
+ select_gplayer_channel(gpd, gpl, SELECT_INVERT);
+ }
+ else {
+ deselect_gpencil_layers(data, 0);
+ select_gplayer_channel(gpd, gpl, SELECT_INVERT);
+ }
+ }
+ }
+ break;
default:
return;
}
@@ -4482,7 +4805,7 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case RIGHTMOUSE:
/* Clicking in the channel area */
if ((G.v2d->mask.xmin) && (mval[0] < NAMEWIDTH)) {
- if (datatype == ACTCONT_ACTION) {
+ if (ELEM(datatype, ACTCONT_ACTION, ACTCONT_GPENCIL)) {
/* mouse is over action channels */
if (G.qual == LR_CTRLKEY)
numbuts_action();
@@ -4832,8 +5155,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..14269080b1f
--- /dev/null
+++ b/source/blender/src/editaction_gpencil.c
@@ -0,0 +1,548 @@
+/**
+ * $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 (void *data, short mode)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter, sel=1;
+
+ /* filter data */
+ filter= ACTFILTER_VISIBLE;
+ actdata_filter(&act_data, filter, data, 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;
+ 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;
+
+ /* 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) {
+ bGPdata *gpd= (bGPdata *)ale->owner;
+ 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/editarmature.c b/source/blender/src/editarmature.c
index 6310dd0a262..d0f44263fb7 100644
--- a/source/blender/src/editarmature.c
+++ b/source/blender/src/editarmature.c
@@ -2709,6 +2709,32 @@ void show_all_armature_bones(void)
BIF_undo_push("Reveal Bones");
}
+/* Sets editmode transform locks for bones (adds if lock==1, clears otherwise) */
+void set_locks_armature_bones(short lock)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL)) {
+ if (lock)
+ ebone->flag |= BONE_EDITMODE_LOCKED;
+ else
+ ebone->flag &= ~BONE_EDITMODE_LOCKED;
+ }
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ if (lock)
+ BIF_undo_push("Lock Bones");
+ else
+ BIF_undo_push("Unlock Bones");
+}
+
/* check for null, before calling! */
static void bone_connect_to_existing_parent(EditBone *bone)
{
diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c
index 4c7334c55e0..98f4f1bb46f 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, L_MOUSE)) {
+ return;
+ }
+ else if(fromlib) {
if(node_mouse_groupheader(snode)==0)
node_mouse_select(snode, event);
}
@@ -2394,7 +2421,10 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
case RIGHTMOUSE:
- if(find_indicated_socket(snode, &actnode, &actsock, SOCK_IN)) {
+ if(gpencil_do_paint(sa, R_MOUSE)) {
+ return;
+ }
+ else if(find_indicated_socket(snode, &actnode, &actsock, SOCK_IN)) {
if(actsock->flag & SOCK_SEL) {
snode->edittree->selin= NULL;
actsock->flag&= ~SOCK_SEL;
@@ -2541,8 +2571,13 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
case DELKEY:
case XKEY:
- if(fromlib) fromlib= -1;
- else node_delete(snode);
+ if(G.qual==LR_ALTKEY) {
+ gpencil_delete_menu();
+ }
+ else {
+ if(fromlib) fromlib= -1;
+ else node_delete(snode);
+ }
break;
}
}
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
index 6af4f47ed11..2f9addb106e 100644
--- a/source/blender/src/editobject.c
+++ b/source/blender/src/editobject.c
@@ -2760,7 +2760,7 @@ void special_editmenu(void)
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
}
else if(G.obedit->type==OB_ARMATURE) {
- nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6");
+ nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6|%l|Lock%x7|Unlock%x8");
if(nr==1)
subdivide_armature(1);
if(nr==2) {
@@ -2773,6 +2773,10 @@ void special_editmenu(void)
else if(ELEM3(nr, 4, 5, 6)) {
armature_autoside_names(nr-4);
}
+ else if(nr==7)
+ set_locks_armature_bones(1);
+ else if(nr==8)
+ set_locks_armature_bones(0);
}
else if(G.obedit->type==OB_LATTICE) {
static float weight= 1.0f;
diff --git a/source/blender/src/editseq.c b/source/blender/src/editseq.c
index f9432f8e69a..12019a9dab9 100644
--- a/source/blender/src/editseq.c
+++ b/source/blender/src/editseq.c
@@ -122,13 +122,28 @@ Sequence *get_last_seq()
if(!_last_seq_init) {
Editing *ed;
Sequence *seq;
+ Sequence *l_sel = NULL;
+ Sequence *l_act = NULL;
ed= G.scene->ed;
if(!ed) return NULL;
- for(seq= ed->seqbasep->first; seq; seq=seq->next)
+ for(seq= ed->seqbasep->first; seq; seq=seq->next) {
+ if(seq->flag & SEQ_ACTIVE)
+ l_act = seq;
if(seq->flag & SELECT)
- _last_seq= seq;
+ l_sel = seq;
+ }
+
+ if (l_act) {
+ _last_seq = l_act;
+ } else {
+ _last_seq = l_sel;
+ }
+
+ if (_last_seq) {
+ _last_seq->flag |= SEQ_ACTIVE;
+ }
_last_seq_init = 1;
}
@@ -138,12 +153,23 @@ Sequence *get_last_seq()
void set_last_seq(Sequence *seq)
{
+ if (_last_seq_init && _last_seq) {
+ _last_seq->flag &= ~SEQ_ACTIVE;
+ }
+
_last_seq = seq;
_last_seq_init = 1;
+
+ if (_last_seq) {
+ _last_seq->flag |= SEQ_ACTIVE;
+ }
}
-void clear_last_seq(Sequence *seq)
+void clear_last_seq()
{
+ if (_last_seq_init && _last_seq) {
+ _last_seq->flag &= ~SEQ_ACTIVE;
+ }
_last_seq = NULL;
_last_seq_init = 0;
}
@@ -2261,6 +2287,8 @@ static Sequence *dupli_seq(Sequence *seq)
"handled in duplicate!\nExpect a crash"
" now...\n");
}
+
+ seqn->flag &= ~SEQ_ACTIVE;
return seqn;
}
diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c
new file mode 100644
index 00000000000..24ed6a7b0ba
--- /dev/null
+++ b/source/blender/src/gpencil.c
@@ -0,0 +1,1232 @@
+/**
+ * $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;
+}
+
+/* -------- 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)
+{
+ 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)
+{
+ bGPdata *gpd= gpencil_data_getactive(NULL);
+ short mode;
+
+ /* only show menu if it will be relevant */
+ if (gpd == NULL) return;
+
+ mode= pupmenu("Grease Pencil 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 5000
+
+/* Hardcoded sensitivity thresholds... */
+// TODO: one day, these might be added to the UI if it is necessary
+ /* minimum number of pixels mouse should move before new point created */
+#define MIN_MANHATTEN_PX 3
+ /* minimum length of new segment before new point can be added */
+#define MIN_EUCLIDEAN_PX 20
+
+/* ------ */
+
+/* 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;
+ }
+}
+
+/* check if the current mouse position is suitable for adding a new point */
+static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2])
+{
+ short dx= abs(mval[0] - pmval[0]);
+ short dy= abs(mval[1] - pmval[1]);
+
+ /* check if mouse moved at least certain distance on both axes (best case) */
+ if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
+ return 1;
+
+ /* check if the distance since the last point is significant enough */
+ else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX)
+ return 1;
+
+ /* mouse 'didn't move' */
+ else
+ return 0;
+}
+
+/* add current stroke-point to buffer (returns whether point was successfully added) */
+static short gp_stroke_addpoint (tGPsdata *p, short mval[2], 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;
+
+ // fixme: currently disabled as it damages too much sometimes
+ return;
+
+ /* 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, short mousebutton)
+{
+ /* 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;
+
+ /* set 'eraser' for this stroke if using eraser or right-mouse in action */
+ if ( get_activedevice() == 2 || (mousebutton & R_MOUSE) ) {
+ p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
+
+ // for now: eraser isn't ready for prime-time yet, so no painting available here yet
+ p->status= GP_STATUS_ERROR;
+ return;
+ }
+
+ /* check if points will need to be made in view-aligned 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 (remove jitter) */
+ gp_stroke_smooth(p);
+
+ /* check if doing eraser or not */
+ if (p->gpd->sbuffer_sflag & GP_STROKE_ERASER) {
+ /* get rid of relevant sections of strokes */
+ }
+ else {
+ /* 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_plus(SPACE_ACTION, 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, mousebutton);
+ 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 (gp_stroke_filtermval(&p, mval, prevmval)) {
+ /* 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, short mousebutton)
+{
+ bGPdata *gpd = gpencil_data_getactive(sa);
+ 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 (!(gpd->flag & GP_DATA_LMBPLOCK) && (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..4bb7bb9677e 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,95 @@ 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->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);
-
- uiClearButLock();
+ /* 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");
- 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");
- }
- 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");
+ /* MODE-DEPENDENT DRAWING */
+ if (G.saction->mode != SACTCONT_GPENCIL) {
+ /* 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 19e2e4b6245..e7b5b176979 100644
--- a/source/blender/src/interface.c
+++ b/source/blender/src/interface.c
@@ -532,7 +532,7 @@ static int ui_but_copy_paste(uiBut *but, char mode)
/* give butfunc the original text too */
/* feature used for bone renaming, channels, etc */
if(but->func_arg2==NULL) {
- strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
+ strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
but->func_arg2= backstr;
}
strncpy(but->poin, but_copypaste_str, but->max);
@@ -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;
@@ -5648,6 +5651,8 @@ static int ui_auto_themecol(uiBut *but)
// (weak!) detect if it is a blockloop
if(but->block->dt == UI_EMBOSSP) return TH_MENU_ITEM;
return TH_BUT_POPUP;
+ case ROUNDBOX:
+ return TH_PANEL;
default:
return TH_BUT_NEUTRAL;
}
diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c
index e7041e60003..83ae449b989 100644
--- a/source/blender/src/interface_draw.c
+++ b/source/blender/src/interface_draw.c
@@ -2351,7 +2351,7 @@ static void ui_draw_roundbox(uiBut *but)
{
glEnable(GL_BLEND);
- BIF_ThemeColorShadeAlpha(TH_PANEL, but->a2, but->a2);
+ BIF_ThemeColorShadeAlpha(but->themecol, but->a2, but->a2);
uiSetRoundBox(but->a1);
gl_round_box(GL_POLYGON, but->x1, but->y1, but->x2, but->y2, but->min);
diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c
index 683b06aafc4..a8e864998b1 100644
--- a/source/blender/src/outliner.c
+++ b/source/blender/src/outliner.c
@@ -68,6 +68,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_utildefines.h"
@@ -698,6 +699,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
te->name= md->name;
+ te->directdata = md;
if (md->type==eModifierType_Lattice) {
outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
@@ -3523,6 +3525,27 @@ static void restrictbutton_r_lay_cb(void *poin, void *poin2)
allqueue(REDRAWBUTSSCENE, 0);
}
+static void restrictbutton_modifier_cb(void *poin, void *poin2)
+{
+ Object *ob = (Object *)poin;
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ object_handle_update(ob);
+ countall();
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+}
+
+static void restrictbutton_bone_cb(void *poin, void *poin2)
+{
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
static void namebutton_cb(void *tep, void *oldnamep)
{
SpaceOops *soops= curarea->spacedata.first;
@@ -3631,7 +3654,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBas
uiBut *bt;
TreeElement *te;
TreeStoreElem *tselem;
- Object *ob;
+ Object *ob = NULL;
for(te= lb->first; te; te= te->next) {
tselem= TREESTORE(te);
@@ -3639,7 +3662,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBas
/* objects have toggle-able restriction flags */
if(tselem->type==0 && te->idcode==ID_OB) {
ob = (Object *)tselem->id;
-
+
uiBlockSetEmboss(block, UI_EMBOSSN);
bt= uiDefIconButBitS(block, ICONTOG, OB_RESTRICT_VIEW, REDRAWALL, ICON_RESTRICT_VIEW_OFF,
(int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ob->restrictflag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
@@ -3685,6 +3708,51 @@ static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBas
uiBlockSetEmboss(block, UI_EMBOSS);
}
+ else if(tselem->type==TSE_MODIFIER) {
+ ModifierData *md= (ModifierData *)te->directdata;
+ ob = (Object *)tselem->id;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, REDRAWALL, ICON_RESTRICT_VIEW_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ /*
+ bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Editmode, REDRAWALL, VICON_EDIT,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+ uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+ */
+
+ bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, REDRAWALL, ICON_RESTRICT_RENDER_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability");
+ uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+ }
+ else if(tselem->type==TSE_POSE_CHANNEL) {
+ bPoseChannel *pchan= (bPoseChannel *)te->directdata;
+ Bone *bone = pchan->bone;
+
+ ob = (Object *)tselem->id;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, REDRAWALL, ICON_RESTRICT_VIEW_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+ }
+ else if(tselem->type==TSE_EBONE) {
+ EditBone *ebone= (EditBone *)te->directdata;
+
+ ob = (Object *)tselem->id;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, REDRAWALL, ICON_RESTRICT_VIEW_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+ }
}
if((tselem->flag & TSE_CLOSED)==0) outliner_draw_restrictbuts(block, soops, &te->subtree);
diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c
index cc08bf53a72..b054b435002 100644
--- a/source/blender/src/poseobject.c
+++ b/source/blender/src/poseobject.c
@@ -180,27 +180,26 @@ bPoseChannel *get_active_posechannel (Object *ob)
return NULL;
}
-/* if a selected or active bone is protected, throw error and return 1 */
+/* if a selected or active bone is protected, throw error (oonly if warn==1) and return 1 */
/* only_selected==1 : the active bone is allowed to be protected */
-static int pose_has_protected_selected(Object *ob, int only_selected)
+static short pose_has_protected_selected(Object *ob, short only_selected, short warn)
{
-
/* check protection */
- if(ob->proxy) {
+ if (ob->proxy) {
bPoseChannel *pchan;
bArmature *arm= ob->data;
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if(pchan->bone && (pchan->bone->layer & arm->layer)) {
- if(pchan->bone->layer & arm->layer_protected) {
- if(only_selected && (pchan->bone->flag & BONE_ACTIVE));
- else if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED))
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone->layer & arm->layer_protected) {
+ if (only_selected && (pchan->bone->flag & BONE_ACTIVE));
+ else if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED))
break;
}
}
}
- if(pchan) {
- error("Cannot change Proxy protected bones");
+ if (pchan) {
+ if (warn) error("Cannot change Proxy protected bones");
return 1;
}
}
@@ -540,7 +539,7 @@ void pose_clear_IK(void)
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
- if(pose_has_protected_selected(ob, 0))
+ if(pose_has_protected_selected(ob, 0, 1))
return;
if(okee("Remove IK constraint(s)")==0) return;
@@ -581,7 +580,7 @@ void pose_clear_constraints(void)
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
- if(pose_has_protected_selected(ob, 0))
+ if(pose_has_protected_selected(ob, 0, 1))
return;
if(okee("Remove Constraints")==0) return;
@@ -612,38 +611,49 @@ void pose_copy_menu(void)
Object *ob= OBACT;
bArmature *arm= ob->data;
bPoseChannel *pchan, *pchanact;
- short nr;
+ short nr=0;
int i=0;
/* paranoia checks */
- if(!ob && !ob->pose) return;
- if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+ if (ELEM(NULL, ob, ob->pose)) return;
+ if ((ob==G.obedit) || (ob->flag & OB_POSEMODE)==0) return;
/* find active */
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if(pchan->bone->flag & BONE_ACTIVE) break;
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->bone->flag & BONE_ACTIVE)
+ break;
}
- if(pchan==NULL) return;
-
- if(pose_has_protected_selected(ob, 1))
- return;
-
+ if (pchan==NULL) return;
pchanact= pchan;
- i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
- if (i<25)
- nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
- else
- nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
+ /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changable,
+ * but for constraints (just add local constraints)
+ */
+ if (pose_has_protected_selected(ob, 1, 0)) {
+ i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5");
+ else
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4");
+ }
+ else {
+ i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
+ else
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
+ }
- if(nr==-1) return;
- if(nr!=5) {
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if( (arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan!=pchanact)
- ) {
+ if (nr <= 0)
+ return;
+
+ if (nr != 5) {
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if ( (arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan != pchanact) )
+ {
switch (nr) {
case 1: /* Local Location */
VECCOPY(pchan->loc, pchanact->loc);
@@ -656,13 +666,26 @@ void pose_copy_menu(void)
break;
case 4: /* All Constraints */
{
- free_constraints(&pchan->constraints);
- copy_constraints(&pchan->constraints, &pchanact->constraints);
- pchan->constflag = pchanact->constflag;
+ ListBase tmp_constraints = {NULL, NULL};
- if (ob->pose) {
- ob->pose->flag |= POSE_RECALC;
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ copy_constraints(&tmp_constraints, &pchanact->constraints);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ bConstraint *con;
+
+ /* add proxy-local tags */
+ for (con= tmp_constraints.first; con; con= con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
}
+ addlisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
+
+ if (ob->pose)
+ ob->pose->flag |= POSE_RECALC;
}
break;
case 6: /* Transform Locks */
@@ -703,12 +726,13 @@ void pose_copy_menu(void)
}
}
}
- } else { /* constraints, optional */
+ }
+ else { /* constraints, optional (note: max we can have is 24 constraints) */
bConstraint *con, *con_back;
int const_toggle[24];
- ListBase const_copy={0, 0};
+ ListBase const_copy = {NULL, NULL};
- duplicatelist (&const_copy, &(pchanact->constraints));
+ duplicatelist(&const_copy, &(pchanact->constraints));
/* build the puplist of constraints */
for (con = pchanact->constraints.first, i=0; con; con=con->next, i++){
@@ -723,32 +747,46 @@ void pose_copy_menu(void)
/* now build a new listbase from the options selected */
for (i=0, con=const_copy.first; con; i++) {
+ /* if not selected, free/remove it from the list */
if (!const_toggle[i]) {
con_back= con->next;
BLI_freelinkN(&const_copy, con);
con= con_back;
- } else {
+ }
+ else
con= con->next;
- }
}
/* Copy the temo listbase to the selected posebones */
- for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- if( (arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan!=pchanact)
- ) {
- free_constraints(&pchan->constraints);
- copy_constraints(&pchan->constraints, &const_copy);
- pchan->constflag = pchanact->constflag;
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if ( (arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan!=pchanact) )
+ {
+ ListBase tmp_constraints = {NULL, NULL};
+
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ copy_constraints(&tmp_constraints, &const_copy);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ bConstraint *con;
+
+ /* add proxy-local tags */
+ for (con= tmp_constraints.first; con; con= con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
+ }
+ addlisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
}
}
BLI_freelistN(&const_copy);
update_pose_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
- if (ob->pose) {
+ if (ob->pose)
ob->pose->flag |= POSE_RECALC;
- }
}
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
@@ -808,7 +846,7 @@ void paste_posebuf (int flip)
/*
// disabled until protected bones in proxies follow the rules everywhere else!
- if(pose_has_protected_selected(ob, 1))
+ if(pose_has_protected_selected(ob, 1, 1))
return;
*/
@@ -1249,7 +1287,7 @@ void pose_flip_names(void)
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
- if(pose_has_protected_selected(ob, 0))
+ if(pose_has_protected_selected(ob, 0, 1))
return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
@@ -1282,7 +1320,7 @@ void pose_autoside_names(short axis)
if (ELEM(NULL, ob, ob->pose)) return;
if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
- if (pose_has_protected_selected(ob, 0))
+ if (pose_has_protected_selected(ob, 0, 1))
return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
@@ -1415,7 +1453,7 @@ void pose_movetolayer(void)
/* pose-channel layers */
bPoseChannel *pchan;
- if (pose_has_protected_selected(ob, 0))
+ if (pose_has_protected_selected(ob, 0, 1))
return;
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
diff --git a/source/blender/src/sequence.c b/source/blender/src/sequence.c
index 9426548dc38..7e2ffc3ba63 100644
--- a/source/blender/src/sequence.c
+++ b/source/blender/src/sequence.c
@@ -1473,8 +1473,8 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
dy = sy;
if (seq->flag & SEQ_USE_TRANSFORM) {
- dx = seqrectx;
- dy = seqrecty;
+ dx = G.scene->r.xsch;
+ dy = G.scene->r.ysch;
}
if (c.top + c.bottom >= se->ibuf->y ||
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 58420604c83..c30f6ca9f54 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,21 +1195,28 @@ 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, L_MOUSE)) return;
if(BIF_do_manipulator(sa)) return;
}
+ else if(event==RIGHTMOUSE) {
+ if(gpencil_do_paint(sa, R_MOUSE)) return;
+ }
/* swap mouse buttons based on user preference */
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 +1954,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");
@@ -2705,6 +2714,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case DELKEY:
if(G.qual==0 || G.qual==LR_SHIFTKEY)
delete_context_selected();
+ if(G.qual==LR_ALTKEY)
+ gpencil_delete_menu();
break;
case YKEY:
if((G.qual==0) && (G.obedit)) {
@@ -4816,6 +4827,14 @@ 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, L_MOUSE)) return;
+ }
+ else if (event == RIGHTMOUSE) {
+ if(gpencil_do_paint(sa, R_MOUSE)) return;
+ }
+
/* swap mouse buttons based on user preference */
if (U.flag & USER_LMOUSESELECT) {
if (event == LEFTMOUSE) {
@@ -4829,11 +4848,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);
@@ -5088,6 +5107,10 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if((G.qual==0))
del_seq();
}
+ else if(G.qual==LR_ALTKEY) {
+ if(sseq->mainb)
+ gpencil_delete_menu();
+ }
break;
case PAD1: case PAD2: case PAD4: case PAD8:
seq_viewzoom(event, (G.qual & LR_SHIFTKEY)==0);
@@ -6241,6 +6264,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 +6308,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 +6343,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 +6363,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 562d9a4934d..8f83434e528 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"
@@ -1087,6 +1089,8 @@ static void createTransArmatureVerts(TransInfo *t)
VECCOPY (td->center, td->iloc);
td->loc= ebo->tail;
td->flag= TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
Mat3CpyMat3(td->smtx, smtx);
Mat3CpyMat3(td->mtx, mtx);
@@ -1102,6 +1106,8 @@ static void createTransArmatureVerts(TransInfo *t)
VECCOPY (td->center, td->iloc);
td->loc= ebo->head;
td->flag= TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
Mat3CpyMat3(td->smtx, smtx);
Mat3CpyMat3(td->mtx, mtx);
@@ -2474,6 +2480,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 +2794,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 +2867,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 +2946,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 +2978,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 +2994,38 @@ static void createTransActionData(TransInfo *t)
/* allocate memory for data */
t->total= count;
+
t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
- if (t->mode == TFM_TIME_SLIDE)
+ td= t->data;
+
+ if (datatype == ACTCONT_GPENCIL) {
+ if (t->mode == TFM_TIME_SLIDE) {
+ t->customData= MEM_callocN((sizeof(float)*2)+(sizeof(tGPFtransdata)*count), "TimeSlide + tGPFtransdata");
+ tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
+ }
+ else {
+ t->customData= MEM_callocN(sizeof(tGPFtransdata)*count, "tGPFtransdata");
+ tfd= (tGPFtransdata *)(t->customData);
+ }
+ }
+ else if (t->mode == TFM_TIME_SLIDE)
t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
- td= t->data;
/* loop 2: build transdata array */
for (ale= act_data.first; ale; ale= ale->next) {
- Ipo *ipo= (Ipo *)ale->key_data;
-
- td= IpoToTransData(td, ipo, ob, side, cfra);
+ if (ale->type == ACTTYPE_GPLAYER) {
+ bGPDlayer *gpl= (bGPDlayer *)ale->data;
+ int i;
+
+ i = GPLayerToTransData(td, tfd, gpl, side, cfra);
+ td += i;
+ tfd += i;
+ }
+ else {
+ Ipo *ipo= (Ipo *)ale->key_data;
+
+ td= IpoToTransData(td, ipo, ob, side, cfra);
+ }
}
/* check if we're supposed to be setting minx/maxx for TimeSlide */
@@ -3673,6 +3877,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/transform_manipulator.c b/source/blender/src/transform_manipulator.c
index 050360887b4..709879f142b 100644
--- a/source/blender/src/transform_manipulator.c
+++ b/source/blender/src/transform_manipulator.c
@@ -170,6 +170,13 @@ static void stats_pose(View3D *v3d, bPoseChannel *pchan)
}
}
+/* for editmode*/
+static void stats_editbone(View3D *v3d, EditBone *ebo)
+{
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &v3d->twdrawflag);
+}
+
/* only counts the parent selection, and tags transform flag */
/* bad call... should re-use method from transform_conversion once */
static void count_bone_select(TransInfo *t, bArmature *arm, ListBase *lb, int do_it)
@@ -258,6 +265,9 @@ int calc_manipulator_stats(ScrArea *sa)
calc_tw_center(ebo->head);
totsel++;
}
+ if (ebo->flag & BONE_SELECTED) {
+ stats_editbone(v3d, ebo);
+ }
}
}
}
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;
}