From 5959df8bf85776b4129a58346b99047a7b6dceaa Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 22 Dec 2008 08:13:25 +0000 Subject: 2.5 - Action Editor / Dopesheet Initial commit of drawing code for Action Editor / Dopesheet. By default, the Dopesheet is now enabled (like in AnimSys2). There are still a few unresolved problems (like bad alpha blending for icons, and keyframes still not being drawn). However, these will be resolved in due course. --- source/blender/editors/animation/anim_draw.c | 78 ++ source/blender/editors/animation/anim_filter.c | 88 +- .../editors/animation/anim_keyframes_draw.c | 701 +++++++++++ source/blender/editors/include/ED_anim_api.h | 76 +- source/blender/editors/include/ED_keyframes_draw.h | 99 ++ source/blender/editors/include/UI_resources.h | 7 + source/blender/editors/interface/resources.c | 9 + source/blender/editors/space_action/action_draw.c | 1321 ++++++++++++++++++++ .../blender/editors/space_action/action_intern.h | 9 +- source/blender/editors/space_action/space_action.c | 20 +- source/blender/editors/space_view3d/drawarmature.c | 26 +- source/blender/makesdna/DNA_userdef_types.h | 5 +- 12 files changed, 2361 insertions(+), 78 deletions(-) create mode 100644 source/blender/editors/animation/anim_keyframes_draw.c create mode 100644 source/blender/editors/include/ED_keyframes_draw.h create mode 100644 source/blender/editors/space_action/action_draw.c (limited to 'source') diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 5485ed9e61e..aea4b0bbf1d 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -42,8 +42,10 @@ #include "BLI_blenlib.h" +#include "BKE_action.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_ipo.h" #include "BKE_object.h" #include "BKE_screen.h" #include "BKE_utildefines.h" @@ -177,3 +179,79 @@ void ANIM_draw_previewrange (const bContext *C, View2D *v2d) } /* *************************************************** */ +/* KEYFRAME DRAWING UTILITIES */ + +/* Obtain the Object providing NLA-scaling for the given channel (if applicable) */ +Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale) +{ + /* sanity checks */ + if (ac == NULL) + return NULL; + + /* handling depends on the type of animation-context we've got */ + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_IPO)) { + /* Action Editor (action mode) or Ipo Editor (ipo mode): + * Only use if editor is not pinned, and active object has action + */ + if (ac->obact && ac->obact->action) { + /* Action Editor */ + if (ac->datatype == ANIMCONT_ACTION) { + SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + + if (saction->pin == 0) + return ac->obact; + } + /* IPO Editor */ + else if (ac->datatype == ANIMCONT_IPO) { + SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; + + if (sipo->pin == 0) + return ac->obact; + } + } + } + else if ((ac->datatype == ANIMCONT_DOPESHEET) && (ale)) { + /* Dopesheet: + * Only if channel is available, and is owned by an Object with an Action + */ + if ((ale->id) && (GS(ale->id->name) == ID_OB)) { + Object *ob= (Object *)ale->id; + + if (ob->action) + return ob; + } + } + + /* no appropriate object found */ + return NULL; +} + +/* Set/clear temporary mapping of coordinates from 'local-action' time to 'global-nla-scaled' time + * - the old mapping is stored in a static var, but that shouldn't be too bad as UI drawing + * (where this is called) is single-threaded anyway + */ +// XXX was called: map_active_strip() +void ANIM_nla_mapping_draw(gla2DDrawInfo *di, Object *ob, short restore) +{ + static rctf stored; + + if (restore) { + /* restore un-mapped coordinates */ + gla2DSetMap(di, &stored); + } + else { + /* set mapped coordinates */ + rctf map; + + gla2DGetMap(di, &stored); + map= stored; + + map.xmin= get_action_frame(ob, map.xmin); + map.xmax= get_action_frame(ob, map.xmax); + + if (map.xmin == map.xmax) map.xmax += 1.0f; + gla2DSetMap(di, &map); + } +} + +/* *************************************************** */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 19dafc439dc..d4b9f9fff93 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -140,86 +140,110 @@ Key *actedit_get_shapekeys (const bContext *C, SpaceAction *saction) } /* Get data being edited in Action Editor (depending on current 'mode') */ -static void *actedit_get_context (const bContext *C, SpaceAction *saction, short *datatype) +static short actedit_get_context (const bContext *C, bAnimContext *ac, SpaceAction *saction) { - Scene *scene= CTX_data_scene(C); - /* sync settings with current view status, then return appropriate data */ switch (saction->mode) { case SACTCONT_ACTION: /* 'Action Editor' */ /* if not pinned, sync with active object */ if (saction->pin == 0) { - if (OBACT) - saction->action = OBACT->action; + if (ac->obact) + saction->action = ac->obact->action; else saction->action= NULL; } - - *datatype= ANIMCONT_ACTION; - return saction->action; + + ac->datatype= ANIMCONT_ACTION; + ac->data= saction->action; + + ac->mode= saction->mode; + return 1; case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */ - *datatype= ANIMCONT_SHAPEKEY; - return actedit_get_shapekeys(C, saction); + ac->datatype= ANIMCONT_SHAPEKEY; + ac->data= actedit_get_shapekeys(C, saction); + + ac->mode= saction->mode; + return 1; case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled... - *datatype=ANIMCONT_GPENCIL; - return CTX_wm_screen(C); // FIXME: add that dopesheet type thing here! - break; + ac->datatype=ANIMCONT_GPENCIL; + ac->data= CTX_wm_screen(C); // FIXME: add that dopesheet type thing here! + + ac->mode= saction->mode; + return 1; case SACTCONT_DOPESHEET: /* DopeSheet */ /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source= (ID *)scene; + saction->ads.source= (ID *)ac->scene; - *datatype= ANIMCONT_DOPESHEET; - return &saction->ads; + ac->datatype= ANIMCONT_DOPESHEET; + ac->data= &saction->ads; + + ac->mode= saction->mode; + return 1; default: /* unhandled yet */ - *datatype= ANIMCONT_NONE; - return NULL; + ac->datatype= ANIMCONT_NONE; + ac->data= NULL; + + ac->mode= -1; + return 0; } } /* ----------- Private Stuff - IPO Editor ------------- */ /* Get data being edited in IPO Editor (depending on current 'mode') */ -static void *ipoedit_get_context (const bContext *C, SpaceIpo *sipo, short *datatype) +static short ipoedit_get_context (const bContext *C, bAnimContext *ac, SpaceIpo *sipo) { // XXX FIXME... - return NULL; + return 0; } /* ----------- Public API --------------- */ -/* Obtain current anim-data context from Blender Context info */ -void *ANIM_animdata_get_context (const bContext *C, short *datatype) +/* Obtain current anim-data context from Blender Context info + * - AnimContext to write to is provided as pointer to var on stack so that we don't have + * allocation/freeing costs (which are not that avoidable with channels). + * - + */ +short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) { - ScrArea *sa= CTX_wm_area(C); + ScrArea *sa= CTX_wm_area(C); // XXX it is assumed that this will always be valid + ARegion *ar= CTX_wm_region(C); + Scene *scene= CTX_data_scene(C); + + /* clear old context info */ + if (ac == NULL) return 0; + memset(ac, 0, sizeof(bAnimContext)); - /* set datatype to 'None' for convenience */ - if (datatype == NULL) return NULL; - *datatype= ANIMCONT_NONE; - if (sa == NULL) return NULL; /* highly unlikely to happen, but still! */ + /* set default context settings */ + ac->scene= scene; + ac->obact= (scene && scene->basact)? scene->basact->object : NULL; + ac->sa= sa; + ac->spacetype= sa->spacetype; + ac->regiontype= ar->regiontype; /* context depends on editor we are currently in */ switch (sa->spacetype) { case SPACE_ACTION: { SpaceAction *saction= (SpaceAction *)CTX_wm_space_data(C); - return actedit_get_context(C, saction, datatype); + return actedit_get_context(C, ac, saction); } break; case SPACE_IPO: { SpaceIpo *sipo= (SpaceIpo *)CTX_wm_space_data(C); - return ipoedit_get_context(C, sipo, datatype); + return ipoedit_get_context(C, ac, sipo); } break; } /* nothing appropriate */ - return NULL; + return 0; } /* ************************************************************ */ @@ -1208,6 +1232,10 @@ void ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, sho case ANIMCONT_DOPESHEET: animdata_filter_dopesheet(anim_data, data, filter_mode); break; + + case ANIMCONT_IPO: + // FIXME: this will be used for showing a single IPO-block (not too useful from animator perspective though!) + break; } /* remove any weedy entries */ diff --git a/source/blender/editors/animation/anim_keyframes_draw.c b/source/blender/editors/animation/anim_keyframes_draw.c new file mode 100644 index 00000000000..2f8d1be784e --- /dev/null +++ b/source/blender/editors/animation/anim_keyframes_draw.c @@ -0,0 +1,701 @@ +/** + * $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 +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#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 + +/* *************************** Keyframe Drawing *************************** */ + +static void add_bezt_to_keycolumnslist(ListBase *keys, BezTriple *bezt) +{ + /* The equivilant of add_to_cfra_elem except this version + * makes ActKeyColumns - one of the two datatypes required + * for action editor drawing. + */ + ActKeyColumn *ak, *akn; + + if (ELEM(NULL, keys, bezt)) return; + + /* try to any existing key to replace, or where to insert after */ + for (ak= keys->last; ak; ak= ak->prev) { + /* do because of double keys */ + if (ak->cfra == bezt->vec[1][0]) { + /* set selection status and 'touched' status */ + if (BEZSELECTED(bezt)) ak->sel = SELECT; + ak->modified += 1; + + return; + } + else if (ak->cfra < bezt->vec[1][0]) break; + } + + /* add new block */ + akn= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); + if (ak) BLI_insertlinkafter(keys, ak, akn); + else BLI_addtail(keys, akn); + + akn->cfra= bezt->vec[1][0]; + akn->modified += 1; + + // TODO: handle type = bezt->h1 or bezt->h2 + akn->handle_type= 0; + + if (BEZSELECTED(bezt)) + akn->sel = SELECT; + else + akn->sel = 0; +} + +static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index) +{ + /* The equivilant of add_to_cfra_elem except this version + * makes ActKeyBlocks - one of the two datatypes required + * for action editor drawing. + */ + ActKeyBlock *ab, *abn; + BezTriple *beztn=NULL, *prev=NULL; + BezTriple *bezt; + int v; + + /* get beztriples */ + beztn= (icu->bezt + index); + + /* we need to go through all beztriples, as they may not be in order (i.e. during transform) */ + for (v=0, bezt=icu->bezt; vtotvert; v++, bezt++) { + /* skip if beztriple is current */ + if (v != index) { + /* check if beztriple is immediately before */ + if (beztn->vec[1][0] > bezt->vec[1][0]) { + /* check if closer than previous was */ + if (prev) { + if (prev->vec[1][0] < bezt->vec[1][0]) + prev= bezt; + } + else { + prev= bezt; + } + } + } + } + + /* check if block needed - same value(s)? + * -> firstly, handles must have same central value as each other + * -> secondly, handles which control that section of the curve must be constant + */ + if ((!prev) || (!beztn)) return; + if (IS_EQ(beztn->vec[1][1], prev->vec[1][1])==0) return; + if (IS_EQ(beztn->vec[1][1], beztn->vec[0][1])==0) return; + if (IS_EQ(prev->vec[1][1], prev->vec[2][1])==0) return; + + /* try to find a keyblock that starts on the previous beztriple + * Note: we can't search from end to try to optimise this as it causes errors there's + * an A ___ B |---| B situation + */ + // FIXME: here there is a bug where we are trying to get the summary for the following channels + // A|--------------|A ______________ B|--------------|B + // A|------------------------------------------------|A + // A|----|A|---|A|-----------------------------------|A + for (ab= blocks->first; ab; ab= ab->next) { + /* check if alter existing block or add new block */ + if (ab->start == prev->vec[1][0]) { + /* set selection status and 'touched' status */ + if (BEZSELECTED(beztn)) ab->sel = SELECT; + ab->modified += 1; + + return; + } + else if (ab->start < prev->vec[1][0]) break; + } + + /* add new block */ + abn= MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock"); + if (ab) BLI_insertlinkbefore(blocks, ab, abn); + else BLI_addtail(blocks, abn); + + abn->start= prev->vec[1][0]; + abn->end= beztn->vec[1][0]; + abn->val= beztn->vec[1][1]; + + if (BEZSELECTED(prev) || BEZSELECTED(beztn)) + abn->sel = SELECT; + else + abn->sel = 0; + abn->modified = 1; +} + +/* helper function - find actkeycolumn that occurs on cframe */ +static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe) +{ + ActKeyColumn *ak, *ak2; + + if (keys==NULL) + return NULL; + + /* search from both ends at the same time, and stop if we find match or if both ends meet */ + for (ak=keys->first, ak2=keys->last; ak && ak2; ak=ak->next, ak2=ak2->prev) { + /* return whichever end encounters the frame */ + if (ak->cfra == cframe) + return ak; + if (ak2->cfra == cframe) + return ak2; + + /* no matches on either end, so return NULL */ + if (ak == ak2) + return NULL; + } + + return NULL; +} + +#if 0 // disabled, as some intel cards have problems with this +/* Draw a simple diamond shape with a filled in center (in screen space) */ +static void draw_key_but(int x, int y, short w, short h, int sel) +{ + int xmin= x, ymin= y; + int xmax= x+w-1, ymax= y+h-1; + int xc= (xmin+xmax)/2, yc= (ymin+ymax)/2; + + /* interior - hardcoded colors (for selected and unselected only) */ + if (sel) glColor3ub(0xF1, 0xCA, 0x13); + else glColor3ub(0xE9, 0xE9, 0xE9); + + glBegin(GL_QUADS); + glVertex2i(xc, ymin); + glVertex2i(xmax, yc); + glVertex2i(xc, ymax); + glVertex2i(xmin, yc); + glEnd(); + + + /* outline */ + glColor3ub(0, 0, 0); + + glBegin(GL_LINE_LOOP); + glVertex2i(xc, ymin); + glVertex2i(xmax, yc); + glVertex2i(xc, ymax); + glVertex2i(xmin, yc); + glEnd(); +} +#endif + +static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos) +{ + ActKeyColumn *ak; + ActKeyBlock *ab; + + glEnable(GL_BLEND); + + /* draw keyblocks */ + if (blocks) { + for (ab= blocks->first; ab; ab= ab->next) { + short startCurves, endCurves, totCurves; + + /* find out how many curves occur at each keyframe */ + ak= cfra_find_actkeycolumn(keys, ab->start); + startCurves = (ak)? ak->totcurve: 0; + + ak= cfra_find_actkeycolumn(keys, ab->end); + endCurves = (ak)? ak->totcurve: 0; + + /* only draw keyblock if it appears in at all of the keyframes at lowest end */ + if (!startCurves && !endCurves) + continue; + else + totCurves = (startCurves>endCurves)? endCurves: startCurves; + + if (ab->totcurve >= totCurves) { + int sc_xa, sc_xb, sc_y; + + /* get co-ordinates of block */ + // XXX only use x-coordinates... y are dummy ones! + gla2DDrawTranslatePt(di, ab->start, ypos, &sc_xa, &sc_y); + gla2DDrawTranslatePt(di, ab->end, ypos, &sc_xb, &sc_y); + + /* draw block */ + if (ab->sel) + UI_ThemeColor4(TH_STRIP_SELECT); + else + UI_ThemeColor4(TH_STRIP); + glRectf((float)sc_xa, (float)ypos-3, (float)sc_xb, (float)ypos+5); + } + } + } + + /* draw keys */ + if (keys) { + for (ak= keys->first; ak; ak= ak->next) { + int sc_x, sc_y; + + /* get co-ordinate to draw at */ + // XXX only use x-coordinates... y are dummy ones! + gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y); + + /* draw using icons - old way which is slower but more proven */ + if (ak->sel & SELECT)UI_icon_draw_aspect((float)sc_x-7, (float)ypos-6, ICON_SPACE2, 1.0f); + else UI_icon_draw_aspect((float)sc_x-7, (float)ypos-6, ICON_SPACE3, 1.0f); + + /* draw using OpenGL - slightly uglier but faster */ + // NOTE: disabled for now, as some intel cards seem to have problems with this + //draw_key_but(sc_x-5, sc_y-4, 11, 11, (ak->sel & SELECT)); + } + } + + glDisable(GL_BLEND); +} + +void draw_object_channel(gla2DDrawInfo *di, ActKeysInc *aki, Object *ob, float ypos) +{ + ListBase keys = {0, 0}; + ListBase blocks = {0, 0}; + + ob_to_keylist(ob, &keys, &blocks, aki); + draw_keylist(di, &keys, &blocks, ypos); + + BLI_freelistN(&keys); + BLI_freelistN(&blocks); +} + +void draw_ipo_channel(gla2DDrawInfo *di, ActKeysInc *aki, Ipo *ipo, float ypos) +{ + ListBase keys = {0, 0}; + ListBase blocks = {0, 0}; + + ipo_to_keylist(ipo, &keys, &blocks, aki); + draw_keylist(di, &keys, &blocks, ypos); + + BLI_freelistN(&keys); + BLI_freelistN(&blocks); +} + +void draw_icu_channel(gla2DDrawInfo *di, ActKeysInc *aki, IpoCurve *icu, float ypos) +{ + ListBase keys = {0, 0}; + ListBase blocks = {0, 0}; + + icu_to_keylist(icu, &keys, &blocks, aki); + draw_keylist(di, &keys, &blocks, ypos); + + BLI_freelistN(&keys); + BLI_freelistN(&blocks); +} + +void draw_agroup_channel(gla2DDrawInfo *di, ActKeysInc *aki, bActionGroup *agrp, float ypos) +{ + ListBase keys = {0, 0}; + ListBase blocks = {0, 0}; + + agroup_to_keylist(agrp, &keys, &blocks, aki); + draw_keylist(di, &keys, &blocks, ypos); + + BLI_freelistN(&keys); + BLI_freelistN(&blocks); +} + +void draw_action_channel(gla2DDrawInfo *di, ActKeysInc *aki, bAction *act, float ypos) +{ + ListBase keys = {0, 0}; + ListBase blocks = {0, 0}; + + action_to_keylist(act, &keys, &blocks, aki); + draw_keylist(di, &keys, &blocks, ypos); + + BLI_freelistN(&keys); + BLI_freelistN(&blocks); +} + +void draw_gpl_channel(gla2DDrawInfo *di, ActKeysInc *aki, bGPDlayer *gpl, float ypos) +{ + ListBase keys = {0, 0}; + + 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) +{ + bConstraintChannel *conchan; + Key *key= ob_get_key(ob); + + if (ob) { + bDopeSheet *ads= (aki)? (aki->ads) : NULL; + int filterflag; + + /* get filterflag */ + if (ads) + filterflag= ads->filterflag; + else if ((aki) && (aki->actmode == -1)) /* only set like this by NLA */ + filterflag= ADS_FILTER_NLADUMMY; + else + filterflag= 0; + + /* Add object keyframes */ + if ((ob->ipo) && !(filterflag & ADS_FILTER_NOIPOS)) + ipo_to_keylist(ob->ipo, keys, blocks, aki); + + /* Add action keyframes */ + if ((ob->action) && !(filterflag & ADS_FILTER_NOACTS)) + action_nlascaled_to_keylist(ob, ob->action, keys, blocks, aki); + + /* Add shapekey keyframes (only if dopesheet allows, if it is available) */ + if ((key && key->ipo) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) + ipo_to_keylist(key->ipo, keys, blocks, aki); + + /* Add material keyframes (only if dopesheet allows, if it is available) */ + if ((ob->totcol) && !(filterflag & ADS_FILTER_NOMAT)) { + short a; + + for (a=0; atotcol; a++) { + Material *ma= give_current_material(ob, a); + + if (ELEM(NULL, ma, ma->ipo) == 0) + ipo_to_keylist(ma->ipo, keys, blocks, aki); + } + } + + /* Add object data keyframes */ + switch (ob->type) { + case OB_CAMERA: /* ------- Camera ------------ */ + { + Camera *ca= (Camera *)ob->data; + if ((ca->ipo) && !(ads->filterflag & ADS_FILTER_NOCAM)) + ipo_to_keylist(ca->ipo, keys, blocks, aki); + } + break; + case OB_LAMP: /* ---------- Lamp ----------- */ + { + Lamp *la= (Lamp *)ob->data; + if ((la->ipo) && !(ads->filterflag & ADS_FILTER_NOLAM)) + ipo_to_keylist(la->ipo, keys, blocks, aki); + } + break; + case OB_CURVE: /* ------- Curve ---------- */ + { + Curve *cu= (Curve *)ob->data; + if ((cu->ipo) && !(ads->filterflag & ADS_FILTER_NOCUR)) + ipo_to_keylist(cu->ipo, keys, blocks, aki); + } + break; + } + + /* Add constraint keyframes */ + if (!(filterflag & ADS_FILTER_NOCONSTRAINTS)) { + for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) { + if (conchan->ipo) + ipo_to_keylist(conchan->ipo, keys, blocks, aki); + } + } + } +} + +static short bezt_in_aki_range (ActKeysInc *aki, BezTriple *bezt) +{ + /* when aki == NULL, we don't care about range */ + if (aki == NULL) + return 1; + + /* if start and end are both 0, then don't care about range */ + if (IS_EQ(aki->start, 0) && IS_EQ(aki->end, 0)) + return 1; + + /* if nla-scaling is in effect, apply appropriate scaling adjustments */ + if (aki->ob) { + float frame= get_action_frame_inv(aki->ob, bezt->vec[1][0]); + return IN_RANGE(frame, aki->start, aki->end); + } + else { + /* check if in range */ + return IN_RANGE(bezt->vec[1][0], aki->start, aki->end); + } +} + +void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks, ActKeysInc *aki) +{ + BezTriple *bezt; + ActKeyColumn *ak, *ak2; + ActKeyBlock *ab, *ab2; + int v; + + if (icu && icu->totvert) { + /* loop through beztriples, making ActKeys and ActKeyBlocks */ + bezt= icu->bezt; + + for (v=0; vtotvert; v++, bezt++) { + /* only if keyframe is in range (optimisation) */ + if (bezt_in_aki_range(aki, bezt)) { + add_bezt_to_keycolumnslist(keys, bezt); + if (blocks) add_bezt_to_keyblockslist(blocks, icu, v); + } + } + + /* update the number of curves that elements have appeared in */ + if (keys) { + for (ak=keys->first, ak2=keys->last; ak && ak2; ak=ak->next, ak2=ak2->prev) { + if (ak->modified) { + ak->modified = 0; + ak->totcurve += 1; + } + + if (ak == ak2) + break; + + if (ak2->modified) { + ak2->modified = 0; + ak2->totcurve += 1; + } + } + } + if (blocks) { + for (ab=blocks->first, ab2=blocks->last; ab && ab2; ab=ab->next, ab2=ab2->prev) { + if (ab->modified) { + ab->modified = 0; + ab->totcurve += 1; + } + + if (ab == ab2) + break; + + if (ab2->modified) { + ab2->modified = 0; + ab2->totcurve += 1; + } + } + } + } +} + +void ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks, ActKeysInc *aki) +{ + IpoCurve *icu; + + if (ipo) { + for (icu= ipo->curve.first; icu; icu= icu->next) + icu_to_keylist(icu, keys, blocks, aki); + } +} + +void agroup_to_keylist(bActionGroup *agrp, ListBase *keys, ListBase *blocks, ActKeysInc *aki) +{ + bActionChannel *achan; + bConstraintChannel *conchan; + + if (agrp) { + /* loop through action channels */ + for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) { + if (VISIBLE_ACHAN(achan)) { + /* firstly, add keys from action channel's ipo block */ + if (achan->ipo) + ipo_to_keylist(achan->ipo, keys, blocks, aki); + + /* then, add keys from constraint channels */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { + if (conchan->ipo) + ipo_to_keylist(conchan->ipo, keys, blocks, aki); + } + } + } + } +} + +void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki) +{ + bActionChannel *achan; + bConstraintChannel *conchan; + + if (act) { + /* loop through action channels */ + for (achan= act->chanbase.first; achan; achan= achan->next) { + /* firstly, add keys from action channel's ipo block */ + if (achan->ipo) + ipo_to_keylist(achan->ipo, keys, blocks, aki); + + /* then, add keys from constraint channels */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { + if (conchan->ipo) + ipo_to_keylist(conchan->ipo, keys, blocks, aki); + } + } + } +} + +void action_nlascaled_to_keylist(Object *ob, bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki) +{ + bActionChannel *achan; + bConstraintChannel *conchan; + Object *oldob= NULL; + + /* although apply and clearing NLA-scaling pre-post creating keylist does impact on performance, + * the effects should be fairly minimal, as we're already going through the keyframes multiple times + * already for blocks too... + */ + if (act) { + /* if 'aki' is provided, store it's current ob to restore later as it might not be the same */ + if (aki) { + oldob= aki->ob; + aki->ob= ob; + } + + /* loop through action channels */ + for (achan= act->chanbase.first; achan; achan= achan->next) { + /* firstly, add keys from action channel's ipo block + * - scaling correction only does times for center-points, so should be faster + */ + if (achan->ipo) { + //actstrip_map_ipo_keys(ob, achan->ipo, 0, 1); // XXX + ipo_to_keylist(achan->ipo, keys, blocks, aki); + //actstrip_map_ipo_keys(ob, achan->ipo, 1, 1); // XXX + } + + /* then, add keys from constraint channels + * - scaling correction only does times for center-points, so should be faster + */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) { + if (conchan->ipo) { + //actstrip_map_ipo_keys(ob, conchan->ipo, 0, 1); // XXX + ipo_to_keylist(conchan->ipo, keys, blocks, aki); + //actstrip_map_ipo_keys(ob, conchan->ipo, 1, 1); // XXX + } + } + } + + /* if 'aki' is provided, restore ob */ + if (aki) + aki->ob= oldob; + } +} + +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= (float)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/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 61065cd970d..f6996bbb07e 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -33,12 +33,43 @@ struct ID; struct ListBase; struct bContext; struct View2D; +struct gla2DDrawInfo; +struct Object; struct bActionGroup; /* ************************************************ */ /* ANIMATION CHANNEL FILTERING */ -/* --------------- Data Types -------------------- */ +/* --------------- Context --------------------- */ + +/* This struct defines a structure used for animation-specific + * 'context' information + */ +typedef struct bAnimContext { + void *data; /* data to be filtered for use in animation editor */ + short datatype; /* type of data eAnimCont_Types */ + + short mode; /* editor->mode */ + short spacetype; /* sa->spacetype */ + short regiontype; /* active region -> type (channels or main) */ + struct ScrArea *sa; /* editor */ + + struct Scene *scene; /* active scene */ + struct Object *obact; /* active object */ +} bAnimContext; + +/* Main Data container types */ +// XXX was ACTCONT_* +typedef enum eAnimCont_Types { + ANIMCONT_NONE = 0, /* invalid or no data */ + ANIMCONT_ACTION, /* action (bAction) */ + ANIMCONT_SHAPEKEY, /* shapekey (Key) */ + ANIMCONT_GPENCIL, /* grease pencil (screen) */ + ANIMCONT_DOPESHEET, /* dopesheet (bDopesheet) */ + ANIMCONT_IPO, /* single IPO (Ipo) */ +} eAnimCont_Types; + +/* --------------- Channels -------------------- */ /* This struct defines a structure used for quick and uniform access for * channels of animation data @@ -109,15 +140,7 @@ typedef enum eAnim_KeyType { ALE_GROUP, /* Action Group summary */ } eAnim_KeyType; -/* Main Data container types */ -// XXX was ACTCONT_* -typedef enum eAnimCont_Types { - ANIMCONT_NONE = 0, /* invalid or no data */ - ANIMCONT_ACTION, /* action (bAction) */ - ANIMCONT_SHAPEKEY, /* shapekey (Key) */ - ANIMCONT_GPENCIL, /* grease pencil (screen) */ - ANIMCONT_DOPESHEET, /* dopesheet (bDopesheet) */ -} eAnimCont_Types; +/* ----------------- Filtering -------------------- */ /* filtering flags - under what circumstances should a channel be added */ // XXX was ACTFILTER_* @@ -179,13 +202,28 @@ typedef enum eAnimFilter_Flags { #define EDITABLE_GPL(gpl) ((gpl->flag & GP_LAYER_LOCKED)==0) #define SEL_GPL(gpl) ((gpl->flag & GP_LAYER_ACTIVE) || (gpl->flag & GP_LAYER_SELECT)) +/* -------------- Channel Defines -------------- */ + +/* channel heights */ +#define ACHANNEL_HEIGHT 16 +#define ACHANNEL_HEIGHT_HALF 8 +#define ACHANNEL_SKIP 2 +#define ACHANNEL_STEP (ACHANNEL_HEIGHT + ACHANNEL_SKIP) + // FIXME: needs to be renamed... +#define NAMEWIDTH 190 + /* ---------------- API -------------------- */ /* Obtain list of filtered Animation channels to operate on */ void ANIM_animdata_filter(struct ListBase *anim_data, int filter_mode, void *data, short datatype); /* Obtain current anim-data context from Blender Context info */ -void *ANIM_animdata_get_context(const struct bContext *C, short *datatype); +/** Example usage (example to be removed...): + // get editor data + if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL)) + return; + */ +short ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac); /* ************************************************ */ /* DRAWING API */ @@ -210,11 +248,23 @@ void ANIM_draw_cfra(const bContext *C, struct View2D *v2d, short flag); /* ------------- Preview Range Drawing -------------- */ -// XXX should preview range get its own file? - /* main call to draw preview range curtains */ void ANIM_draw_previewrange(const bContext *C, struct View2D *v2d); +/* ************************************************* */ +/* ASSORTED TOOLS */ + +/* ------------- NLA-Mapping ----------------------- */ + +/* Obtain the Object providing NLA-scaling for the given channel if applicable */ +struct Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale); + +/* set/clear temporary mapping of coordinates from 'local-action' time to 'global-nla-scaled' time */ +void ANIM_nla_mapping_draw(struct gla2DDrawInfo *di, struct Object *ob, short restore); + +/* ------------- xxx macros ----------------------- */ +#define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT)) + /* ************************************************* */ /* OPERATORS */ diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h new file mode 100644 index 00000000000..a1ddd6b6bed --- /dev/null +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -0,0 +1,99 @@ +/** + * $Id: BDR_drawaction.h 17579 2008-11-26 11:01:56Z 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): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BDR_DRAWACTION_H +#define BDR_DRAWACTION_H + +struct BezTriple; +struct Ipo; +struct IpoCurve; +struct gla2DDrawInfo; +struct bAction; +struct bActionGroup; +struct bActListElem; +struct Object; +struct ListBase; +struct bGPDlayer; + +/* ****************************** Base Structs ****************************** */ + +/* Keyframe Column Struct */ +typedef struct ActKeyColumn { + struct ActKeyColumn *next, *prev; + short sel, handle_type; + float cfra; + + /* only while drawing - used to determine if long-keyframe needs to be drawn */ + short modified; + short totcurve; +} ActKeyColumn; + +/* 'Long Keyframe' Struct */ +typedef struct ActKeyBlock { + struct ActKeyBlock *next, *prev; + short sel, handle_type; + float val; + float start, end; + + /* only while drawing - used to determine if block needs to be drawn */ + short modified; + short totcurve; +} ActKeyBlock; + + +/* Inclusion-Range Limiting Struct (optional) */ +typedef struct ActKeysInc { + struct bDopeSheet *ads; /* dopesheet data (for dopesheet mode) */ + struct Object *ob; /* owner object for NLA-scaling info (if Object channels, is just Object) */ + short actmode; /* mode of the Action Editor (-1 is for NLA) */ + + float start, end; /* frames (global-time) to only consider keys between */ // XXX not used anymore! +} ActKeysInc; + +/* ******************************* Methods ****************************** */ + +/* Channel Drawing */ +void draw_icu_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct IpoCurve *icu, float ypos); +void draw_ipo_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct Ipo *ipo, float ypos); +void draw_agroup_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct bActionGroup *agrp, float ypos); +void draw_action_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct bAction *act, float ypos); +void draw_object_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct Object *ob, float ypos); +void draw_gpl_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct bGPDlayer *gpl, float ypos); + +/* Keydata Generation */ +void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void agroup_to_keylist(struct bActionGroup *agrp, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void action_to_keylist(struct bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void action_nlascaled_to_keylist(struct Object *ob, struct bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void ob_to_keylist(struct Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki); +void gpl_to_keylist(struct bGPDlayer *gpl, ListBase *keys, ListBase *blocks, ActKeysInc *aki); + +#endif /* BDR_DRAWACTION_H */ + diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 461150ef045..a7a4c2814c3 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -527,6 +527,13 @@ enum { TH_EDGE_SHARP, TH_EDITMESH_ACTIVE, + + TH_HANDLE_VERTEX, + TH_HANDLE_VERTEX_SELECT, + TH_HANDLE_VERTEX_SIZE, + + TH_DOPESHEET_CHANNELOB, + TH_DOPESHEET_CHANNELSUBOB, }; /* XXX WARNING: previous is saved in file, so do not change order! */ diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 6e498a5fc29..4022fefa33b 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -430,6 +430,10 @@ void ui_theme_init_userdef(void) SETCOL(btheme->tipo.hilite, 0x60, 0xc0, 0x40, 255); btheme->tipo.vertex_size= 3; + SETCOL(btheme->tipo.handle_vertex, 0xff, 0x70, 0xff, 255); + SETCOL(btheme->tipo.handle_vertex_select, 0xff, 0xff, 0x70, 255); + btheme->tipo.handle_vertex_size= 3; + /* space file */ /* to have something initialized */ btheme->tfile= btheme->tv3d; @@ -453,6 +457,11 @@ void ui_theme_init_userdef(void) SETCOL(btheme->tact.hilite, 17, 27, 60, 100); // bar SETCOL(btheme->tact.strip_select, 0xff, 0xff, 0xaa, 255); SETCOL(btheme->tact.strip, 0xe4, 0x9c, 0xc6, 255); + SETCOL(btheme->tact.group, 0x39, 0x7d, 0x1b, 255); + SETCOL(btheme->tact.group_active, 0x7d, 0xe9, 0x60, 255); + SETCOL(btheme->tact.ds_channel, 0x36, 0x13, 0xca, 255); + SETCOL(btheme->tact.ds_subchannel, 0x60, 0x43, 0xd2, 255); + /* space nla */ btheme->tnla= btheme->tv3d; 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 +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#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:"); + + special= ICON_IMAGE_COL; + } + break; + + default: + { + sprintf(name, ""); + 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); +} diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index cd4886f50c4..82ff4926082 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -28,11 +28,18 @@ #ifndef ED_ACTION_INTERN_H #define ED_ACTION_INTERN_H +struct bContext; +struct SpaceAction; +struct ARegion; + /* internal exports only */ +/* action_draw.c */ +void draw_channel_names(const struct bContext *C, struct SpaceAction *saction, struct ARegion *ar); +void draw_channel_strips(const struct bContext *C, struct SpaceAction *saction, struct ARegion *ar); /* action_header.c */ -void action_header_buttons(const bContext *C, ARegion *ar); +void action_header_buttons(const struct bContext *C, struct ARegion *ar); #endif /* ED_ACTION_INTERN_H */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index af43f65af82..e3ccc313909 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -29,6 +29,7 @@ #include #include +#include "DNA_listBase.h" #include "DNA_action_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" @@ -58,6 +59,7 @@ #include "UI_view2d.h" #include "ED_anim_api.h" +#include "ED_keyframes_draw.h" #include "ED_markers.h" #include "action_intern.h" // own include @@ -177,15 +179,16 @@ static void action_main_area_draw(const bContext *C, ARegion *ar) glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(C, v2d); - + /* time grid */ unit= (saction->flag & SACTION_DRAWTIME)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES; grid= UI_view2d_grid_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy); UI_view2d_grid_draw(C, v2d, grid, V2D_GRIDLINES_ALL); UI_view2d_grid_free(grid); - /* data? */ - + /* data */ + draw_channel_strips(C, saction, ar); + /* current frame */ if (saction->flag & SACTION_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS; if ((saction->flag & SACTION_NODRAWCFRANUM)==0) flag |= DRAWCFRA_SHOW_NUMBOX; @@ -233,7 +236,7 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) static void action_channel_area_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ - //SpaceAction *saction= C->area->spacedata.first; + SpaceAction *saction= (SpaceAction*)CTX_wm_space_data(C); View2D *v2d= &ar->v2d; View2DScrollers *scrollers; float col[3]; @@ -245,12 +248,9 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) UI_view2d_view_ortho(C, v2d); - /* data... */ - // temp... line for testing - glColor3f(0, 0, 0); - glLineWidth(2.0f); - sdrawline(10, 0, 190, 0); - glLineWidth(1.0f); + /* data */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + draw_channel_names(C, saction, ar); /* reset view matrix */ UI_view2d_view_restore(C); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index c10ceb78282..1eb0b8c2b86 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -70,6 +70,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "ED_keyframes_draw.h" + #include "WM_api.h" #include "WM_types.h" @@ -79,26 +81,6 @@ /* XXX ***************** */ int pose_channel_in_IK_chain() {return 0;} -void ipo_to_keylist() {} -void *ob_get_action() {return NULL;} -void action_to_keylist() {} - -typedef struct ActKeyColumn { - struct ActKeyColumn *next, *prev; - short sel, handle_type; - float cfra; - - /* only while drawing - used to determine if long-keyframe needs to be drawn */ - short modified; - short totcurve; -} ActKeyColumn; -typedef struct ActKeysInc { - struct Object *ob; /* if present, used to find action-scaled time */ - float start, end; /* frames (global-time) to only consider keys between */ -} ActKeysInc; - -/* ******************** */ - /* *************** Armature Drawing - Coloring API ***************************** */ @@ -2192,7 +2174,7 @@ static void draw_pose_paths(View3D *v3d, Object *ob) if (arm->pathflag & ARM_PATH_KFRAS) { /* build list of all keyframes in active action for pchan */ keys.first = keys.last = NULL; - act= ob_get_action(ob); + act= ob->action; if (act) { achan= get_action_channel(act, pchan->name); if (achan) @@ -2338,7 +2320,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, Base *base) static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, Base *base) { Object *ob= base->object; - bAction *act= ob_get_action(ob); + bAction *act= ob->action; bArmature *arm= ob->data; bPose *posen, *poseo; ListBase keys= {NULL, NULL}; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index a8cd905f81c..975403c3a5f 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -90,7 +90,8 @@ typedef struct ThemeSpace { char normal[4]; char bone_solid[4], bone_pose[4]; char strip[4], strip_select[4]; - char cframe[4], pad[4]; + char cframe[4]; + char ds_channel[4], ds_subchannel[4]; // dopesheet char vertex_size, facedot_size; char bpad[2]; @@ -105,7 +106,7 @@ typedef struct ThemeSpace { char handle_vertex[4]; char handle_vertex_select[4]; char handle_vertex_size; - char hpad[7]; + char hpad[3]; } ThemeSpace; -- cgit v1.2.3