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.
This commit is contained in:
Joshua Leung 2008-12-22 08:13:25 +00:00
parent 3c1204024b
commit 5959df8bf8
12 changed files with 2361 additions and 78 deletions

@ -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);
}
}
/* *************************************************** */

@ -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);
/* 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! */
/* clear old context info */
if (ac == NULL) return 0;
memset(ac, 0, sizeof(bAnimContext));
/* 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 */

@ -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 <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
/* *************************** 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; v<icu->totvert; 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; a<ob->totcol; 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; v<icu->totvert; 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;
}
}
}

@ -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 */

@ -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 */

@ -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! */

@ -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;

File diff suppressed because it is too large Load Diff

@ -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 */

@ -29,6 +29,7 @@
#include <string.h>
#include <stdio.h>
#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
@ -184,7 +186,8 @@ static void action_main_area_draw(const bContext *C, ARegion *ar)
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;
@ -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);

@ -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};

@ -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;