diff options
author | Nicholas Bishop <nicholasbishop@gmail.com> | 2008-07-27 23:53:57 +0400 |
---|---|---|
committer | Nicholas Bishop <nicholasbishop@gmail.com> | 2008-07-27 23:53:57 +0400 |
commit | ec66e5e75aa48870823775a38479c647d38b9bc8 (patch) | |
tree | 3c44a2c5d46a9dda95be181fbadd0686ebea866a /source/blender/src | |
parent | 5a3572beecf86bdbdc8fe1589567f5d4d66b095b (diff) | |
parent | f4def51cd3c225cf3bbe7895f729a29a5d4067e5 (diff) |
Merged with r15805
Diffstat (limited to 'source/blender/src')
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; } |