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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2008-12-22 11:13:25 +0300
committerJoshua Leung <aligorith@gmail.com>2008-12-22 11:13:25 +0300
commit5959df8bf85776b4129a58346b99047a7b6dceaa (patch)
tree774e425b507d8b79df31c757f73a1393c56962d4 /source/blender/editors/space_action/action_draw.c
parent3c1204024be5261a6a5c9fb1e2d8f68216136e71 (diff)
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.
Diffstat (limited to 'source/blender/editors/space_action/action_draw.c')
-rw-r--r--source/blender/editors/space_action/action_draw.c1321
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);
+}