This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/editors/space_action/action_draw.c

1256 lines
33 KiB
C

/**
* $Id$
*
* ***** 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_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_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_meta_types.h"
#include "DNA_userdef_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
#include "BKE_action.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.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_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
/* XXX */
extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
/********************************** 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);
x = ACHANNEL_NAMEWIDTH + 1;
y = 0.0f;
uiBlockSetEmboss(block, UI_EMBOSSN);
if (!(G.saction->flag & SACTION_SLIDERS)) {
ACTWIDTH = ACHANNEL_NAMEWIDTH;
but=uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR,
ICON_DISCLOSURE_TRI_RIGHT,
ACHANNEL_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,
ACHANNEL_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 = ACHANNEL_NAMEWIDTH + SLIDERWIDTH;
/* sliders are open so draw them */
BIF_ThemeColor(TH_FACE);
glRects(ACHANNEL_NAMEWIDTH, 0, ACHANNEL_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(C, 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);
x = (float)ACHANNEL_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(ACHANNEL_NAMEWIDTH, (short)G.v2d->cur.ymin, ACHANNEL_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(C, block);
}
#endif // XXX all of this slider stuff will need a rethink
/* ************************************************************************* */
/* Channel List */
/* left hand part */
void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
View2D *v2d= &ar->v2d;
float x= 0.0f, y= 0.0f;
int items, height;
/* build list of channels to draw */
filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
* - this is done to allow the channel list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because channels list is drawn first
* - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin= (float)(-height);
}
/* need to do a view-sync here, so that the keys area doesn't jump around */
UI_view2d_sync(NULL, ac->sa, v2d, V2D_VIEWSYNC_AREA_VERTICAL);
/* loop through channels, and set up drawing depending on their type */
y= (float)ACHANNEL_FIRST;
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[128];
/* determine what needs to be drawn */
switch (ale->type) {
case ANIMTYPE_SCENE: /* scene */
{
Scene *sce= (Scene *)ale->data;
group= 4;
indent= 0;
special= ICON_SCENE_DATA;
/* only show expand if there are any channels */
if (EXPANDED_SCEC(sce))
expand= ICON_TRIA_DOWN;
else
expand= ICON_TRIA_RIGHT;
sel = SEL_SCEC(sce);
strcpy(name, sce->id.name+2);
}
break;
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_DATA;
else
special= ICON_OBJECT_DATA;
/* 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);
strcpy(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);
strcpy(name, act->id.name+2);
}
break;
case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */
{
Object *ob = (Object *)ale->data;
group = 4;
indent = 1;
special = ICON_MATERIAL_DATA;
if (FILTER_MAT_OBJC(ob))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, "Materials");
}
break;
case ANIMTYPE_FILLPARTD: /* object particles (dopesheet) expand widget */
{
Object *ob = (Object *)ale->data;
group = 4;
indent = 1;
special = ICON_PARTICLE_DATA;
if (FILTER_PART_OBJC(ob))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, "Particles");
}
break;
case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */
{
Material *ma = (Material *)ale->data;
group = 0;
indent = 0;
special = ICON_MATERIAL_DATA;
offset = 21;
if (FILTER_MAT_OBJD(ma))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(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_DATA;
if (FILTER_LAM_OBJD(la))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(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_DATA;
if (FILTER_CAM_OBJD(ca))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(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_DATA;
if (FILTER_CUR_OBJD(cu))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, cu->id.name+2);
}
break;
case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */
{
Key *key= (Key *)ale->data;
group = 4;
indent = 1;
special = ICON_SHAPEKEY_DATA; // XXX
if (FILTER_SKE_OBJD(key))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
//sel = SEL_OBJC(base);
strcpy(name, "Shape Keys");
}
break;
case ANIMTYPE_DSWOR: /* world (dopesheet) expand widget */
{
World *wo= (World *)ale->data;
group = 4;
indent = 1;
special = ICON_WORLD_DATA;
if (FILTER_WOR_SCED(wo))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, wo->id.name+2);
}
break;
case ANIMTYPE_DSPART: /* particle (dopesheet) expand widget */
{
ParticleSettings *part= (ParticleSettings*)ale->data;
group = 0;
indent = 0;
special = ICON_PARTICLE_DATA;
offset = 21;
if (FILTER_PART_OBJD(part))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, part->id.name+2);
}
break;
case ANIMTYPE_DSMBALL: /* metaball (dopesheet) expand widget */
{
MetaBall *mb = (MetaBall *)ale->data;
group = 4;
indent = 1;
special = ICON_META_DATA;
if (FILTER_MBALL_OBJD(mb))
expand = ICON_TRIA_DOWN;
else
expand = ICON_TRIA_RIGHT;
strcpy(name, mb->id.name+2);
}
break;
case ANIMTYPE_GROUP: /* action group */
{
bActionGroup *agrp= (bActionGroup *)ale->data;
group= 2;
indent= 0;
special= -1;
if (ale->id) {
/* special exception for materials */
if (GS(ale->id->name) == ID_MA)
offset= 25;
else
offset= 14;
}
else
offset= 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 (agrp->flag & AGRP_MUTED)
mute = ICON_MUTE_IPO_ON;
else
mute = ICON_MUTE_IPO_OFF;
if (EDITABLE_AGRP(agrp))
protect = ICON_UNLOCKED;
else
protect = ICON_LOCKED;
sel = SEL_AGRP(agrp);
strcpy(name, agrp->name);
}
break;
case ANIMTYPE_FCURVE: /* F-Curve channel */
{
FCurve *fcu = (FCurve *)ale->data;
indent = 0;
group= (fcu->grp) ? 1 : 0;
grp= fcu->grp;
if (ale->id) {
/* special exception for materials and particles */
if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) {
offset= 21;
indent= 1;
}
else
offset= 14;
}
else
offset= 0;
if (fcu->flag & FCURVE_MUTED)
mute = ICON_MUTE_IPO_ON;
else
mute = ICON_MUTE_IPO_OFF;
if (fcu->bezt) {
if (EDITABLE_FCU(fcu))
protect = ICON_UNLOCKED;
else
protect = ICON_LOCKED;
}
else
protect = ICON_ZOOMOUT; // XXX editability is irrelevant here, but this icon is temp...
sel = SEL_FCU(fcu);
getname_anim_fcurve(name, ale->id, fcu);
}
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
strcpy(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:%s", view3d_get_name(sa->spacedata.first)); // XXX missing func..
strcpy(name, "3dView");
special= ICON_VIEW3D;
}
break;
case SPACE_NODE:
{
SpaceNode *snode= sa->spacedata.first;
char treetype[12];
if (snode->treetype == 1)
strcpy(treetype, "Composite");
else
strcpy(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
strcpy(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 */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
/* draw backing strip behind channel name */
if (group == 4) {
/* only used in dopesheet... */
if (ELEM(ale->type, ANIMTYPE_SCENE, 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)ACHANNEL_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)ACHANNEL_NAMEWIDTH, ymaxc);
glVertex2f((float)ACHANNEL_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)ACHANNEL_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)ACHANNEL_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)ACHANNEL_NAMEWIDTH, ymaxc);
glVertex2f((float)ACHANNEL_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 normal channels */
UI_icon_draw(x+offset, yminc, special);
offset += 17;
}
}
glDisable(GL_BLEND);
/* draw name */
if (sel)
UI_ThemeColor(TH_TEXT_HI);
else
UI_ThemeColor(TH_TEXT);
offset += 3;
UI_DrawString(x+offset, y-4, name);
/* reset offset - for RHS of panel */
offset = 0;
/* set blending again, as text drawing may clear it */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
/* draw protect 'lock' */
if (protect > -1) {
offset = 16;
UI_icon_draw((float)ACHANNEL_NAMEWIDTH-offset, yminc, protect);
}
/* draw mute 'eye' */
if (mute > -1) {
offset += 16;
UI_icon_draw((float)(ACHANNEL_NAMEWIDTH-offset), yminc, mute);
}
glDisable(GL_BLEND);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
}
/* free tempolary channels */
BLI_freelistN(&anim_data);
}
/* ************************************************************************* */
/* Keyframes */
/* extra padding for lengths (to go under scrollers) */
#define EXTRA_SCROLL_PAD 100.0f
/* draw keyframes in each channel */
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
View2D *v2d= &ar->v2d;
bDopeSheet *ads= &saction->ads;
AnimData *adt= NULL;
float act_start, act_end, y;
int height, items;
char col1[3], col2[3];
char col1a[3], col2a[3];
char col1b[3], col2b[3];
/* get theme colors */
UI_GetThemeColor3ubv(TH_BACK, 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);
/* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
/* if in NLA there's a strip active, map the view */
if (ac->datatype == ANIMCONT_ACTION) {
adt= ANIM_nla_mapping_get(ac, NULL);
/* start and end of action itself */
// TODO: this has not had scaling applied
calc_action_range(ac->data, &act_start, &act_end, 0);
}
/* build list of channels to draw */
filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
* - this is done to allow the channel list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because channels list is drawn first
* - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin= (float)(-height);
/* first backdrop strips */
y= (float)(-ACHANNEL_HEIGHT);
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 sel=0;
/* determine if any need to draw channel */
if (ale->datatype != ALE_NONE) {
/* determine if channel is selected */
switch (ale->type) {
case ANIMTYPE_SCENE:
{
Scene *sce= (Scene *)ale->data;
sel = SEL_SCEC(sce);
}
break;
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_FCURVE:
{
FCurve *fcu = (FCurve *)ale->data;
sel = SEL_FCU(fcu);
}
break;
case ANIMTYPE_GPLAYER:
{
bGPDlayer *gpl = (bGPDlayer *)ale->data;
sel = SEL_GPL(gpl);
}
break;
}
if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
switch (ale->type) {
case ANIMTYPE_SCENE:
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_FILLACTD:
case ANIMTYPE_FILLMATD:
case ANIMTYPE_FILLPARTD:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
{
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(v2d->cur.xmin, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD, (float)y+ACHANNEL_HEIGHT_HALF);
if (ac->datatype == ANIMCONT_ACTION)
glRectf(act_start, (float)y-ACHANNEL_HEIGHT_HALF, act_end, (float)y+ACHANNEL_HEIGHT_HALF);
}
else if (ac->datatype == ANIMCONT_SHAPEKEY) {
/* 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)y-ACHANNEL_HEIGHT_HALF, 1.0f, (float)y+ACHANNEL_HEIGHT_HALF);
/* frames one and higher get a saturated orange background */
glColor4ub(col2[0], col2[1], col2[2], 0x44);
glRectf(1.0f, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD, (float)y+ACHANNEL_HEIGHT_HALF);
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
/* 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)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)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(v2d->cur.xmin, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD, (float)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);
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) {
adt= ANIM_nla_mapping_get(ac, ale);
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_SCE:
draw_scene_channel(v2d, ads, ale->key_data, y);
break;
case ALE_OB:
draw_object_channel(v2d, ads, ale->key_data, y);
break;
case ALE_ACT:
draw_action_channel(v2d, adt, ale->key_data, y);
break;
case ALE_GROUP:
draw_agroup_channel(v2d, adt, ale->data, y);
break;
case ALE_FCURVE:
draw_fcurve_channel(v2d, adt, ale->key_data, y);
break;
case ALE_GPFRAME:
draw_gpl_channel(v2d, ads, ale->data, y);
break;
}
}
}
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) {
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex2f(saction->timeslide, v2d->cur.ymin-EXTRA_SCROLL_PAD);
glVertex2f(saction->timeslide, v2d->cur.ymax);
glEnd();
}
}