diff options
Diffstat (limited to 'source/blender/editors/space_action/action_draw.c')
-rw-r--r-- | source/blender/editors/space_action/action_draw.c | 1321 |
1 files changed, 1321 insertions, 0 deletions
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c new file mode 100644 index 00000000000..c9c309a7f79 --- /dev/null +++ b/source/blender/editors/space_action/action_draw.c @@ -0,0 +1,1321 @@ +/** + * $Id: drawaction.c 17746 2008-12-08 11:19:44Z 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* System includes ----------------------------------------------------- */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +/* Types --------------------------------------------------------------- */ + +#include "DNA_listBase.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_constraint_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "BKE_action.h" +#include "BKE_depsgraph.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_global.h" // XXX remove me! +#include "BKE_context.h" +#include "BKE_utildefines.h" + +/* Everything from source (BIF, BDR, BSE) ------------------------------ */ + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" +#include "UI_text.h" +#include "UI_view2d.h" + +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_keyframes_draw.h" +#include "ED_screen.h" +#include "ED_space_api.h" + +#if 0 // XXX old includes for reference only + #include "BIF_editaction.h" + #include "BIF_editkey.h" + #include "BIF_editnla.h" + #include "BIF_drawgpencil.h" + #include "BIF_keyframing.h" + #include "BIF_language.h" + #include "BIF_space.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_headerbuttons.h" + #include "BSE_time.h" + #include "BSE_view.h" +#endif // XXX old defines for reference only + +/********************************** Slider Stuff **************************** */ + +#if 0 // XXX all of this slider stuff will need a rethink! +/* sliders for shapekeys */ +static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key) +{ + int i; + char str[64]; + float x, y; + uiBlock *block; + uiBut *but; + + /* lets make the shapekey sliders */ + + /* reset the damn myortho2 or the sliders won't draw/redraw + * correctly *grumble* + */ + mywinset(curarea->win); + myortho2(-0.375f, curarea->winx-0.375f, G.v2d->cur.ymin, G.v2d->cur.ymax); + + sprintf(str, "actionbuttonswin %d", curarea->win); + block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSS, UI_HELV, curarea->win); + + x = NAMEWIDTH + 1; + y = 0.0f; + + uiBlockSetEmboss(block, UI_EMBOSSN); + + if (!(G.saction->flag & SACTION_SLIDERS)) { + ACTWIDTH = NAMEWIDTH; + but=uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, + ICON_DISCLOSURE_TRI_RIGHT, + NAMEWIDTH - XIC - 5, (short)y + CHANNELHEIGHT, + XIC,YIC-2, + &(G.saction->flag), 0, 0, 0, 0, + "Show action window sliders"); + /* no hilite, the winmatrix is not correct later on... */ + uiButSetFlag(but, UI_NO_HILITE); + } + else { + but= uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, + ICON_DISCLOSURE_TRI_DOWN, + NAMEWIDTH - XIC - 5, (short)y + CHANNELHEIGHT, + XIC,YIC-2, + &(G.saction->flag), 0, 0, 0, 0, + "Hide action window sliders"); + /* no hilite, the winmatrix is not correct later on... */ + uiButSetFlag(but, UI_NO_HILITE); + + ACTWIDTH = NAMEWIDTH + SLIDERWIDTH; + + /* sliders are open so draw them */ + BIF_ThemeColor(TH_FACE); + + glRects(NAMEWIDTH, 0, NAMEWIDTH+SLIDERWIDTH, curarea->winy); + uiBlockSetEmboss(block, UI_EMBOSS); + for (i=1; i < key->totkey; i++) { + make_rvk_slider(block, ob, i, + (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys"); + + y-=CHANNELHEIGHT+CHANNELSKIP; + + /* see sliderval array in editkey.c */ + if (i >= 255) break; + } + } + uiDrawBlock(block); +} + +static void icu_slider_func(void *voidicu, void *voidignore) +{ + /* the callback for the icu sliders ... copies the + * value from the icu->curval into a bezier at the + * right frame on the right ipo curve (creating both the + * ipo curve and the bezier if needed). + */ + IpoCurve *icu= voidicu; + BezTriple *bezt=NULL; + float cfra, icuval; + + cfra = frame_to_float(CFRA); + if (G.saction->pin==0 && OBACT) + cfra= get_action_frame(OBACT, cfra); + + /* if the ipocurve exists, try to get a bezier + * for this frame + */ + bezt = get_bezt_icu_time(icu, &cfra, &icuval); + + /* create the bezier triple if one doesn't exist, + * otherwise modify it's value + */ + if (bezt == NULL) { + insert_vert_icu(icu, cfra, icu->curval, 0); + } + else { + bezt->vec[1][1] = icu->curval; + } + + /* make sure the Ipo's are properly processed and + * redraw as necessary + */ + sort_time_ipocurve(icu); + testhandles_ipocurve(icu); + + /* nla-update (in case this affects anything) */ + synchronize_action_strips(); + + /* do redraw pushes, and also the depsgraph flushes */ + if (OBACT->pose || ob_get_key(OBACT)) + DAG_object_flush_update(G.scene, OBACT, OB_RECALC); + else + DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB); + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + allqueue(REDRAWIPO, 0); + allspace(REMAKEIPO, 0); + allqueue(REDRAWBUTSALL, 0); +} + +static void make_icu_slider(uiBlock *block, IpoCurve *icu, + int x, int y, int w, int h, char *tip) +{ + /* create a slider for the ipo-curve*/ + uiBut *but; + + if(icu == NULL) return; + + if (IS_EQ(icu->slide_max, icu->slide_min)) { + if (IS_EQ(icu->ymax, icu->ymin)) { + if (ELEM(icu->blocktype, ID_CO, ID_KE)) { + /* hack for constraints and shapekeys (and maybe a few others) */ + icu->slide_min= 0.0; + icu->slide_max= 1.0; + } + else { + icu->slide_min= -100; + icu->slide_max= 100; + } + } + else { + icu->slide_min= icu->ymin; + icu->slide_max= icu->ymax; + } + } + if (icu->slide_min >= icu->slide_max) { + SWAP(float, icu->slide_min, icu->slide_max); + } + + but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "", + x, y , w, h, + &(icu->curval), icu->slide_min, icu->slide_max, + 10, 2, tip); + + uiButSetFunc(but, icu_slider_func, icu, NULL); + + // no hilite, the winmatrix is not correct later on... + uiButSetFlag(but, UI_NO_HILITE); +} + +/* sliders for ipo-curves of active action-channel */ +static void action_icu_buts(SpaceAction *saction) +{ + ListBase act_data = {NULL, NULL}; + bActListElem *ale; + int filter; + void *data; + short datatype; + + char str[64]; + float x, y; + uiBlock *block; + + /* lets make the action sliders */ + + /* reset the damn myortho2 or the sliders won't draw/redraw + * correctly *grumble* + */ + mywinset(curarea->win); + myortho2(-0.375f, curarea->winx-0.375f, G.v2d->cur.ymin, G.v2d->cur.ymax); + + sprintf(str, "actionbuttonswin %d", curarea->win); + block= uiNewBlock (&curarea->uiblocks, str, + UI_EMBOSS, UI_HELV, curarea->win); + + x = (float)NAMEWIDTH + 1; + y = 0.0f; + + uiBlockSetEmboss(block, UI_EMBOSSN); + + if (G.saction->flag & SACTION_SLIDERS) { + /* sliders are open so draw them */ + + /* get editor data */ + data= get_action_context(&datatype); + if (data == NULL) return; + + /* build list of channels to draw */ + filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS); + actdata_filter(&act_data, filter, data, datatype); + + /* draw backdrop first */ + BIF_ThemeColor(TH_FACE); // change this color... it's ugly + glRects(NAMEWIDTH, (short)G.v2d->cur.ymin, NAMEWIDTH+SLIDERWIDTH, (short)G.v2d->cur.ymax); + + uiBlockSetEmboss(block, UI_EMBOSS); + for (ale= act_data.first; ale; ale= ale->next) { + const float yminc= y-CHANNELHEIGHT/2; + const float ymaxc= y+CHANNELHEIGHT/2; + + /* check if visible */ + if ( IN_RANGE(yminc, G.v2d->cur.ymin, G.v2d->cur.ymax) || + IN_RANGE(ymaxc, G.v2d->cur.ymin, G.v2d->cur.ymax) ) + { + /* determine what needs to be drawn */ + switch (ale->type) { + case ACTTYPE_CONCHAN: /* constraint channel */ + { + bActionChannel *achan = (bActionChannel *)ale->owner; + IpoCurve *icu = (IpoCurve *)ale->key_data; + + /* only show if owner is selected */ + if ((ale->ownertype == ACTTYPE_OBJECT) || SEL_ACHAN(achan)) { + make_icu_slider(block, icu, + (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, + "Slider to control current value of Constraint Influence"); + } + } + break; + case ACTTYPE_ICU: /* ipo-curve channel */ + { + bActionChannel *achan = (bActionChannel *)ale->owner; + IpoCurve *icu = (IpoCurve *)ale->key_data; + + /* only show if owner is selected */ + if ((ale->ownertype == ACTTYPE_OBJECT) || SEL_ACHAN(achan)) { + make_icu_slider(block, icu, + (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, + "Slider to control current value of IPO-Curve"); + } + } + break; + case ACTTYPE_SHAPEKEY: /* shapekey channel */ + { + Object *ob= (Object *)ale->id; + IpoCurve *icu= (IpoCurve *)ale->key_data; + + // TODO: only show if object is active + if (icu) { + make_icu_slider(block, icu, + (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-2, + "Slider to control ShapeKey"); + } + else if (ob && ale->index) { + make_rvk_slider(block, ob, ale->index, + (int)x, (int)y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys"); + } + } + break; + } + } + + /* adjust y-position for next one */ + y-=CHANNELHEIGHT+CHANNELSKIP; + } + + /* free tempolary channels */ + BLI_freelistN(&act_data); + } + uiDrawBlock(block); +} + +#endif // XXX all of this slider stuff will need a rethink + + +/********************************** Left-Hand Panel + Generics **************************** */ + +// XXX +extern void gl_round_box(short, float, float, float, float, short); + +/* left hand part */ +void draw_channel_names(const bContext *C, SpaceAction *saction, ARegion *ar) +{ + ListBase anim_data = {NULL, NULL}; + bAnimContext ac; + bAnimListElem *ale; + int filter; + View2D *v2d= &ar->v2d; + float x= 0.0f, y= (float)(-ACHANNEL_HEIGHT_HALF); + + /* determine what type of data we are operating on */ + if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL)) + return; + + /* set default color back to black */ + //glColor3ub(0x00, 0x00, 0x00); + + /* build list of channels to draw */ + filter= (ANIMFILTER_FORDRAWING|ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS); + ANIM_animdata_filter(&anim_data, filter, ac.data, ac.datatype); + + /* loop through channels, and set up drawing depending on their type */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + for (ale= anim_data.first; ale; ale= ale->next) { + const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF); + const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF); + + /* check if visible */ + if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) + { + bActionGroup *grp = NULL; + short indent= 0, offset= 0, sel= 0, group= 0; + int expand= -1, protect = -1, special= -1, mute = -1; + char name[64]; + + /* determine what needs to be drawn */ + switch (ale->type) { + case ANIMTYPE_OBJECT: /* object */ + { + Base *base= (Base *)ale->data; + Object *ob= base->object; + + group= 4; + indent= 0; + + /* icon depends on object-type */ + if (ob->type == OB_ARMATURE) + special= ICON_ARMATURE; + else + special= ICON_OBJECT; + + /* only show expand if there are any channels */ + if (EXPANDED_OBJC(ob)) + expand= ICON_TRIA_DOWN; + else + expand= ICON_TRIA_RIGHT; + + sel = SEL_OBJC(base); + sprintf(name, ob->id.name+2); + } + break; + case ANIMTYPE_FILLACTD: /* action widget */ + { + bAction *act= (bAction *)ale->data; + + group = 4; + indent= 1; + special= ICON_ACTION; + + if (EXPANDED_ACTC(act)) + expand= ICON_TRIA_DOWN; + else + expand= ICON_TRIA_RIGHT; + + sel = SEL_ACTC(act); + sprintf(name, "Action"); + } + break; + case ANIMTYPE_FILLIPOD: /* ipo (dopesheet) expand widget */ + { + Object *ob = (Object *)ale->data; + + group = 4; + indent = 1; + special = ICON_IPO; + + if (FILTER_IPO_OBJC(ob)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + //sel = SEL_OBJC(base); + sprintf(name, "IPO Curves"); + } + break; + case ANIMTYPE_FILLCOND: /* constraint channels (dopesheet) expand widget */ + { + Object *ob = (Object *)ale->data; + + group = 4; + indent = 1; + special = ICON_CONSTRAINT; + + if (FILTER_CON_OBJC(ob)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + //sel = SEL_OBJC(base); + sprintf(name, "Constraints"); + } + break; + case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */ + { + Object *ob = (Object *)ale->data; + + group = 4; + indent = 1; + special = ICON_MATERIAL; + + if (FILTER_MAT_OBJC(ob)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sprintf(name, "Materials"); + } + break; + + + case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */ + { + Material *ma = (Material *)ale->data; + + group = 0; + indent = 0; + special = ICON_MATERIAL; + offset = 21; + + if (FILTER_MAT_OBJD(ma)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sprintf(name, ma->id.name+2); + } + break; + case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */ + { + Lamp *la = (Lamp *)ale->data; + + group = 4; + indent = 1; + special = ICON_LAMP; + + if (FILTER_LAM_OBJD(la)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sprintf(name, la->id.name+2); + } + break; + case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */ + { + Camera *ca = (Camera *)ale->data; + + group = 4; + indent = 1; + special = ICON_CAMERA; + + if (FILTER_CAM_OBJD(ca)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sprintf(name, ca->id.name+2); + } + break; + case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */ + { + Curve *cu = (Curve *)ale->data; + + group = 4; + indent = 1; + special = ICON_CURVE; + + if (FILTER_CUR_OBJD(cu)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sprintf(name, cu->id.name+2); + } + break; + case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */ + { + Key *key= (Key *)ale->data; + + group = 4; + indent = 1; + special = ICON_EDIT; + + if (FILTER_SKE_OBJD(key)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + //sel = SEL_OBJC(base); + sprintf(name, "Shape Keys"); + } + break; + + + case ANIMTYPE_GROUP: /* action group */ + { + bActionGroup *agrp= (bActionGroup *)ale->data; + + group= 2; + indent= 0; + special= -1; + + offset= (ale->id) ? 21 : 0; + + /* only show expand if there are any channels */ + if (agrp->channels.first) { + if (EXPANDED_AGRP(agrp)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + } + + if (EDITABLE_AGRP(agrp)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + + sel = SEL_AGRP(agrp); + sprintf(name, agrp->name); + } + break; + case ANIMTYPE_ACHAN: /* action channel */ + { + bActionChannel *achan= (bActionChannel *)ale->data; + + group= (ale->grp) ? 1 : 0; + grp= ale->grp; + + indent = 0; + special = -1; + + offset= (ale->id) ? 21 : 0; + + if (EXPANDED_ACHAN(achan)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + if (EDITABLE_ACHAN(achan)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + + if (achan->ipo) { + if (achan->ipo->muteipo) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + } + + sel = SEL_ACHAN(achan); + sprintf(name, achan->name); + } + break; + case ANIMTYPE_CONCHAN: /* constraint channel */ + { + bConstraintChannel *conchan = (bConstraintChannel *)ale->data; + + group= (ale->grp) ? 1 : 0; + grp= ale->grp; + + if (ale->id) { + if (ale->ownertype == ANIMTYPE_ACHAN) { + /* for constraint channels under Action in Dopesheet */ + indent= 2; + offset= 21; + } + else { + /* for constraint channels under Object in Dopesheet */ + indent= 2; + offset = 0; + } + } + else { + /* for normal constraint channels in Action Editor */ + indent= 2; + offset= 0; + } + + if (EDITABLE_CONCHAN(conchan)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + + if (conchan->ipo) { + if (conchan->ipo->muteipo) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + } + + sel = SEL_CONCHAN(conchan); + sprintf(name, conchan->name); + } + break; + case ANIMTYPE_ICU: /* ipo-curve channel */ + { + IpoCurve *icu = (IpoCurve *)ale->data; + + indent = 2; + protect = -1; // for now, until this can be supported by others + + group= (ale->grp) ? 1 : 0; + grp= ale->grp; + + if (ale->id) { + if ((GS(ale->id->name)==ID_MA) || (ale->ownertype == ANIMTYPE_ACHAN)) + offset= 21; + else + offset= 0; + } + else + offset= 0; + + if (icu->flag & IPO_MUTE) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + + sel = SEL_ICU(icu); + //if (saction->pin) + // sprintf(name, getname_ipocurve(icu, NULL)); // xxx func to eventually eliminate + //else + // sprintf(name, getname_ipocurve(icu, ac.obact)); // xxx func to eventually eliminate + sprintf(name, "[IPO Curve]"); // FIXME xxx + } + break; + case ANIMTYPE_FILLIPO: /* ipo expand widget */ + { + bActionChannel *achan = (bActionChannel *)ale->data; + + indent = 1; + //special = geticon_ipo_blocktype(achan->ipo->blocktype); // xxx func to eventually eliminate + + group= (ale->grp) ? 1 : 0; + grp= ale->grp; + + offset= (ale->id) ? 21 : 0; + + if (FILTER_IPO_ACHAN(achan)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sel = SEL_ACHAN(achan); + sprintf(name, "IPO Curves"); + } + break; + case ANIMTYPE_FILLCON: /* constraint expand widget */ + { + bActionChannel *achan = (bActionChannel *)ale->data; + + indent = 1; + special = ICON_CONSTRAINT; + + group= (ale->grp) ? 1 : 0; + grp= ale->grp; + + offset= (ale->id) ? 21 : 0; + + if (FILTER_CON_ACHAN(achan)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + sel = SEL_ACHAN(achan); + sprintf(name, "Constraint"); + } + break; + + + case ANIMTYPE_SHAPEKEY: /* shapekey channel */ + { + KeyBlock *kb = (KeyBlock *)ale->data; + + indent = 0; + special = -1; + + offset= (ale->id) ? 21 : 0; + + if (kb->name[0] == '\0') + sprintf(name, "Key %d", ale->index); + else + sprintf(name, kb->name); + } + break; + + case ANIMTYPE_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[%02d]:%s", sa->win, view3d_get_name(sa->spacedata.first)); // XXX missing func.. + 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; + case SPACE_IMAGE: + { + SpaceImage *sima= sa->spacedata.first; + + if (sima->image) + sprintf(name, "Image:%s", sima->image->id.name+2); + else + sprintf(name, "Image:<None>"); + + special= ICON_IMAGE_COL; + } + break; + + default: + { + sprintf(name, "<Unknown GP-Data Source>"); + special= -1; + } + break; + } + } + break; + case ANIMTYPE_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 == 4) { + /* only used in dopesheet... */ + if (ale->type == ANIMTYPE_OBJECT) { + /* object channel - darker */ + UI_ThemeColor(TH_DOPESHEET_CHANNELOB); + uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8)); + gl_round_box(GL_POLYGON, x+offset, yminc, (float)NAMEWIDTH, ymaxc, 8); + } + else { + /* sub-object folders - lighter */ + UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB); + + offset += 7 * indent; + glBegin(GL_QUADS); + glVertex2f(x+offset, yminc); + glVertex2f(x+offset, ymaxc); + glVertex2f((float)NAMEWIDTH, ymaxc); + glVertex2f((float)NAMEWIDTH, yminc); + glEnd(); + + /* clear group value, otherwise we cause errors... */ + group = 0; + } + } + else if (group == 3) { + /* only for gp-data channels */ + UI_ThemeColorShade(TH_GROUP, 20); + uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8)); + gl_round_box(GL_POLYGON, x+offset, yminc, (float)NAMEWIDTH, ymaxc, 8); + } + else if (group == 2) { + /* only for action group channels */ + if (ale->flag & AGRP_ACTIVE) + UI_ThemeColorShade(TH_GROUP_ACTIVE, 10); + else + UI_ThemeColorShade(TH_GROUP, 20); + uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8)); + gl_round_box(GL_POLYGON, x+offset, yminc, (float)NAMEWIDTH, ymaxc, 8); + } + else { + /* for normal channels + * - use 3 shades of color group/standard color for 3 indention level + * - only use group colors if allowed to, and if actually feasible + */ + if ( !(saction->flag & SACTION_NODRAWGCOLORS) && + (grp) && (grp->customCol) ) + { + char cp[3]; + + if (indent == 2) { + VECCOPY(cp, grp->cs.solid); + } + else if (indent == 1) { + VECCOPY(cp, grp->cs.select); + } + else { + VECCOPY(cp, grp->cs.active); + } + + glColor3ub(cp[0], cp[1], cp[2]); + } + else + UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40)); + + indent += group; + offset += 7 * indent; + glBegin(GL_QUADS); + glVertex2f(x+offset, yminc); + glVertex2f(x+offset, ymaxc); + glVertex2f((float)NAMEWIDTH, ymaxc); + glVertex2f((float)NAMEWIDTH, yminc); + glEnd(); + } + + /* draw expand/collapse triangle */ + if (expand > 0) { + UI_icon_draw(x+offset, yminc, expand); + offset += 17; + } + + /* draw special icon indicating certain data-types */ + if (special > -1) { + if (ELEM(group, 3, 4)) { + /* for gpdatablock channels */ + UI_icon_draw(x+offset, yminc, special); + offset += 17; + } + else { + /* for ipo/constraint channels */ + UI_icon_draw(x+offset, yminc, special); + offset += 17; + } + } + + /* draw name */ + if (sel) + UI_ThemeColor(TH_TEXT_HI); + else + UI_ThemeColor(TH_TEXT); + offset += 3; + glRasterPos2f(x+offset, y-4); + UI_DrawString(G.font, name, 0); + + /* reset offset - for RHS of panel */ + offset = 0; + + /* draw protect 'lock' */ + if (protect > -1) { + offset = 16; + UI_icon_draw((float)NAMEWIDTH-offset, yminc, protect); + } + + /* draw mute 'eye' */ + if (mute > -1) { + offset += 16; + UI_icon_draw((float)(NAMEWIDTH-offset), yminc, mute); + } + } + + /* adjust y-position for next one */ + y -= ACHANNEL_STEP; + } + + /* free tempolary channels */ + BLI_freelistN(&anim_data); +} + +static ActKeysInc *init_aki_data(bAnimContext *ac, bAnimListElem *ale) +{ + static ActKeysInc aki; + + /* no need to set settings if wrong context */ + if ((ac->data == NULL) || ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)==0) + return NULL; + + /* if strip is mapped, store settings */ + aki.ob= ANIM_nla_mapping_get(ac, ale); + + if (ac->datatype == ANIMCONT_DOPESHEET) + aki.ads= (bDopeSheet *)ac->data; + else + aki.ads= NULL; + aki.actmode= ac->datatype; + + /* always return pointer... */ + return &aki; +} + + +void draw_channel_strips(const bContext *C, SpaceAction *saction, ARegion *ar) +{ + ListBase anim_data = {NULL, NULL}; + bAnimContext ac; + bAnimListElem *ale; + int filter; + + View2D *v2d= &ar->v2d; + Object *nob= NULL; + gla2DDrawInfo *di; + rcti scr_rct; + + int act_start, act_end, dummy; + float y, sta, end; + + char col1[3], col2[3]; + char col1a[3], col2a[3]; + char col1b[3], col2b[3]; + + + /* get theme colors */ + UI_GetThemeColor3ubv(TH_SHADE2, col2); + UI_GetThemeColor3ubv(TH_HILITE, col1); + UI_GetThemeColor3ubv(TH_GROUP, col2a); + UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a); + + UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b); + UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b); + + /* get editor data */ + if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL)) + return; + + /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */ + scr_rct.xmin= ar->winrct.xmin + ar->v2d.mask.xmin; + scr_rct.ymin= ar->winrct.ymin + ar->v2d.mask.ymin; + scr_rct.xmax= ar->winrct.xmin + ar->v2d.hor.xmax; + scr_rct.ymax= ar->winrct.ymin + ar->v2d.mask.ymax; + di= glaBegin2DDraw(&scr_rct, &v2d->cur); + + /* if in NLA there's a strip active, map the view */ + if (ac.datatype == ANIMCONT_ACTION) { + nob= ANIM_nla_mapping_get(&ac, NULL); + + if (nob) + ANIM_nla_mapping_draw(di, nob, 0); + + /* start and end of action itself */ + calc_action_range(ac.data, &sta, &end, 0); + gla2DDrawTranslatePt(di, sta, 0.0f, &act_start, &dummy); + gla2DDrawTranslatePt(di, end, 0.0f, &act_end, &dummy); + + if (nob) + ANIM_nla_mapping_draw(di, nob, 1); + } + + /* build list of channels to draw */ + filter= (ANIMFILTER_FORDRAWING|ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS); + ANIM_animdata_filter(&anim_data, filter, ac.data, ac.datatype); + + /* first backdrop strips */ + y= (float)(-ACHANNEL_HEIGHT_HALF); + glEnable(GL_BLEND); + for (ale= anim_data.first; ale; ale= ale->next) { + const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF); + const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF); + + /* check if visible */ + if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) + { + int frame1_x, channel_y, sel=0; + + /* determine if any need to draw channel */ + if (ale->datatype != ALE_NONE) { + /* determine if channel is selected */ + switch (ale->type) { + case ANIMTYPE_OBJECT: + { + Base *base= (Base *)ale->data; + sel = SEL_OBJC(base); + } + break; + case ANIMTYPE_GROUP: + { + bActionGroup *agrp = (bActionGroup *)ale->data; + sel = SEL_AGRP(agrp); + } + break; + case ANIMTYPE_ACHAN: + { + bActionChannel *achan = (bActionChannel *)ale->data; + sel = SEL_ACHAN(achan); + } + break; + case ANIMTYPE_CONCHAN: + { + bConstraintChannel *conchan = (bConstraintChannel *)ale->data; + sel = SEL_CONCHAN(conchan); + } + break; + case ANIMTYPE_ICU: + { + IpoCurve *icu = (IpoCurve *)ale->data; + sel = SEL_ICU(icu); + } + break; + case ANIMTYPE_GPLAYER: + { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + sel = SEL_GPL(gpl); + } + break; + } + + if (ELEM(ac.datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { + gla2DDrawTranslatePt(di, v2d->cur.xmin, y, &frame1_x, &channel_y); + + switch (ale->type) { + case ANIMTYPE_OBJECT: + { + if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); + else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); + } + break; + + case ANIMTYPE_FILLIPOD: + case ANIMTYPE_FILLACTD: + case ANIMTYPE_FILLCOND: + case ANIMTYPE_DSSKEY: + { + if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); + else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); + } + break; + + case ANIMTYPE_GROUP: + { + if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); + else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); + } + break; + + default: + { + if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); + else glColor4ub(col2[0], col2[1], col2[2], 0x22); + } + break; + } + + /* draw region twice: firstly backdrop, then the current range */ + glRectf((float)frame1_x, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)v2d->hor.xmax, (float)channel_y+ACHANNEL_HEIGHT_HALF); + + if (ac.datatype == ANIMCONT_ACTION) + glRectf((float)act_start, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)act_end, (float)channel_y+ACHANNEL_HEIGHT_HALF); + } + else if (ac.datatype == ANIMCONT_SHAPEKEY) { + gla2DDrawTranslatePt(di, 1, y, &frame1_x, &channel_y); + + /* all frames that have a frame number less than one + * get a desaturated orange background + */ + glColor4ub(col2[0], col2[1], col2[2], 0x22); + glRectf(0.0f, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)frame1_x, (float)channel_y+ACHANNEL_HEIGHT_HALF); + + /* frames one and higher get a saturated orange background */ + glColor4ub(col2[0], col2[1], col2[2], 0x44); + glRectf((float)frame1_x, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)v2d->hor.xmax, (float)channel_y+ACHANNEL_HEIGHT_HALF); + } + else if (ac.datatype == ANIMCONT_GPENCIL) { + gla2DDrawTranslatePt(di, 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.0f, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)frame1_x, (float)channel_y+ACHANNEL_HEIGHT_HALF); + + /* 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((float)frame1_x, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)v2d->hor.xmax, (float)channel_y+ACHANNEL_HEIGHT_HALF); + } + } + } + + /* Increment the step */ + y -= ACHANNEL_STEP; + } + glDisable(GL_BLEND); + + /* Draw keyframes + * 1) Only channels that are visible in the Action Editor get drawn/evaluated. + * This is to try to optimise this for heavier data sets + * 2) Keyframes which are out of view horizontally are disregarded + */ + y= (float)(-ACHANNEL_HEIGHT_HALF); + for (ale= anim_data.first; ale; ale= ale->next) { + const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF); + const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF); + + /* check if visible */ + if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) + { + /* check if anything to show for this channel */ + if (ale->datatype != ALE_NONE) { + ActKeysInc *aki= init_aki_data(&ac, ale); + nob= ANIM_nla_mapping_get(&ac, ale); + + if (nob) + ANIM_nla_mapping_draw(di, nob, 0); + + /* draw 'keyframes' for each specific datatype */ + switch (ale->datatype) { + case ALE_OB: + draw_object_channel(di, aki, ale->key_data, y); + break; + case ALE_ACT: + draw_action_channel(di, aki, ale->key_data, y); + break; + case ALE_GROUP: + draw_agroup_channel(di, aki, ale->data, y); + break; + case ALE_IPO: + draw_ipo_channel(di, aki, ale->key_data, y); + break; + case ALE_ICU: + draw_icu_channel(di, aki, ale->key_data, y); + break; + case ALE_GPFRAME: + draw_gpl_channel(di, aki, ale->data, y); + break; + } + + if (nob) + ANIM_nla_mapping_draw(di, nob, 1); + } + } + + y-= ACHANNEL_STEP; + } + + /* free tempolary channels used for drawing */ + BLI_freelistN(&anim_data); + + /* black line marking 'current frame' for Time-Slide transform mode */ + if (saction->flag & SACTION_MOVING) { + int frame1_x; + + gla2DDrawTranslatePt(di, saction->timeslide, 0, &frame1_x, &dummy); + cpack(0x0); + + glBegin(GL_LINES); + glVertex2f((float)frame1_x, (float)v2d->mask.ymin - 100); + glVertex2f((float)frame1_x, (float)v2d->mask.ymax); + glEnd(); + } + + glaEnd2DDraw(di); +} |